I’m hunting a tricky bug and I think I need to verify some assumptions I had made that may be really wrong. I’m a ReScript beginner and unfortunately pretty lousy at JS and TS as well… Starting with a first question and seeing where that leads.
- I assumed that the make function of a rescript-react component would NOT be called if the components (record) props would succeed (“referential”) equality tests with the previously passed prop values.
The reason I’m asking this is that it seems to me like the make function is getting called in my code despite it to me really looking like I’m passing prop values that should be equal to the previous ones.
Is 1) a correct or incorrect assumption?
Please post the code in question.
IIRC, React did behave that way at one point, but it doesnt anymore. Any change of state in one component will rerender all of its descendants recursively, and then leaves it to vdom diff to find changes. You can add some bounds on this with React.memo
Thanks for offering to review code! I don’t have an isolated and minimized example ready (it’s part of a big jumbled mess of work in progress at the moment as things often are when experimenting) and I believe that @mouton answered the question and I now think I have a theory of what the bug is. Thank you all the same!
Thanks so much, that’s a great link! I read through some of it and will read all of it later tonight, what a superb resource. I also checked out the React memo docs at memo – React and they expanded on it even more.
Now that I understand that re-renders are always triggered deeply (unless memo is used), my mind moved on and I think I have an idea of my bug (VDOM diffing related for a contenteditable div that I sometimes want re-rendered and sometimes not so as to maintain cursor/selection/etc and other complicated state). I will try a solution idea and might return with a different question if it fails.
Thanks again for the superb link and info! Cheers!
This does bring up a lurking issue with Rescript IMO that ties into the equality conversation in the other thread:
Without referential control in rescript, can we even know when a Memo will be triggered since the language is free, and likely, to produce new objects here and there? This is usually what we want, but it has struck me as a bit nefarious. With some pressure in the low level bindings for mutation in arrays etc, there is also a pressure the other way where some changes wont cause react rerender when you would otherwise expect they did.
That’s an interesting question. As my ReScript/JS/TS skill level is beginner, I know too little about when new objects are created in different situations.
In the context of React component props, almost all of my props are either primitive types (as categorized by the ReScript manual) or records, with the exception of the dispatch function returned by the useReducer function. As evidenced by my thread question, I was under the (faulty) assumption that make wouldn’t even be called if props were (referentially) equal, and I was sort of hoping that the dispatch function would be the same instance on each render and thus equal, so that wasteful re-renders would be prevented.
Now I realize that in order to use React.memo successfully there’s probably quite a bit of research needed for a beginner like me to understand how the Object.is() comparison is done by React on the JS side and also, like you say, when ReScript creates new instances of things and not. If someone knows a lot about it, a section on it in the rescript-react docs would be fantastic, but as a lot of this is behavior under the hood of the language I suppose it might be a tricky moving target to keep correctly documented…?
In the beginning I’d ignore the React.memo, useCallback and dependency arrays. They are needed only for performance optimization, which is not always worth the complexity they introduce.
The number of render function calls shouldn’t affect the work of your program in any way.
Absolutely, the program must work identically either way.
However, since the app I’m building has a lot of text editing (the contenteditable divs i mentioned earlier) every keystroke causes an action-reduce cycle and thus apparently running the rendering functions of every visible component. The app still feels reasonably smooth right now but I might have to do a bit of performance measuring and optimization later on. React.memo might come in handy then, if it’s possible to predict it’s behavior in combination with ReScript immutability/referential control properly.