Imagine that you've built an application with ReactJs containing a hundred elements. Let's say that in some time, the state of component A changes, and for the sake of simplicity we assume it has only one element and no child component.
My question is: how is Virtual DOM updated in response to the state change?
After a few hours of research, I found two contradictory opinions:
The entire Virtual DOM is torn down; then it is rebuilt from scratch
Only the changed elements are updated in the Virtual DOM.
Unfortunately, official documentation is not clear about this. So, can anybody give the correct answer? (please with supporting reference)
[Edit] : Some parts are imcomplete here, think about reading the comment section !
React update a component when its state or a prop changes. It does a comparison between the previous JSX and the new one and re-render only the differences.
If the parent component has its state or a prop changed, it will be updated.
The child will not be refreshed unless a prop from the parent that is passed to it changes.
Note that the useEffect from the child is triggered first. Knowing that, If you do things that update the state in the child component, then it will be re-rendered everytime (Because the usEffect is triggered everytime if you don't set any dependencies).
Test from Stackblitz - Child Effect is triggered first
Article that made me notice it (I didn't know before this answer :D)
Here is how I understand things in React. To be short, the entire virtual DOM isn't rebuilt from scratch, it's not how JSX comparison works.
I don't have much sources about what I said, but here is the explanation about jsx update from the official documentation. Just that should be enough to eliminate the first point of your list.
Related
I have read many blogs on render and commit phase in react. But couldn't understand much exactly. They mention render phase is a slow process and commit phase doesn't takes time.
In simpler words, is rendering checking the current Virtual DOM with previous Virtual DOM starting from the root/or the point where states/props are changed?
And committing is putting the change in the batch which will go in the next batch update to real DOM?
If we consider rendering as a run of diffing algorithm, the function component -
function ReactApp(){
console.log("rendering...");
return (...<Child/>....);
}
function Child(){
console.log("rendering child...");
useEffect(() => {
console.log("mounting child...");
})
return (...);
}
Will render and "rendering..." can be seen in console.
It's mentioned useEffect (all componentDidMount,didupdate,willUnmount) will run only in commit phase.
But if this component has a child component and the parent renders when parents' states changes.
"rendering..." should be visible in console for parent.
"rendering child..." should be visible in console too.
And it does.
But why "mounting child..." can be seen in console, if no states changed for it.
In reconciliation process, only parent's UI update should go into batch.
And child should only be checked by rendering.
This is creating a lot of confusion among words - 'rendering','mounting','committing'.
Also, we can see the changes on changing state instantly, which means real DOM gets updated quickly?
Or the process is quite faster for a human to perceive changes between a react and a non-react app?
If virtual DOM concept is that powerful, why don't browsers already have it in-built?
Sorry if some/all questions seem stupid.
But I really want to know it in a manner I can explain it to a 5 year. Any links to simpler docs would be grateful too.
[This is the Codesandbox with all of the code that exemplifies the issue I'm having. Sorry, SO doesn't allow for proper React code with TSX, etc.]
I have some tabs, naturally, whenever I click on each of them, my state changes (namely selectedTab) and the body that's being rendered. Each tab item has a body that goes with it, the first tab, in my case, has a component that, if you click, a count is increased. Well, whenever the tab changes, that count gets reset. In fact, it's a full-rerender all around.
The problem with doing a full re-render is that - not only is it inefficient, given how the user's gonna use it, but it also adds fuel to the fire: what if the user inputs something on a tab, then switches to another tab to do something else and then back to the original one? He's just lost what he typed in.
Naturally, this can be solved if we render all of the tabs' content upfront and we just play with display: none, and it'd be a good solution, but I'm also trying to learn.
I understand how React re-renders things and why this happens, but is there a way to fix it?
In my case, if you look at useTabs, the content variable simply looks at the corresponding tab's component key and takes outputs that. It's there that, I think, I need to memoize things.
Uhm, I guess you can't prevent calling your custom hook, this will lead to invariant violation error.
These hooks in the component will be executed on each render -> thus 'resets' your tabs.
You should rely on useEffect dependencies argument to run conditional code to see if values needs to be changed.
as long as your in the same app you could use contextApi,react context docs otherwise you can use localstorage, localstorage tutorial
or just create this state in the parent component and pass it down as props?
As much as I know, this are the "phases" on a react lifecycle for a component:
Mounting: Mounting is the stage of rendering the JSX returned by the render method itself.
Updating: Updating is the stage when the state of a component is updated and the application is repainted.
Unmounting: As the name suggests Unmounting is the final step of the component lifecycle where the component is removed from the page.
mounting -> updating -> unmounting
I succesfully used it, but i don't know how to mix those 3 "phases" with :
- commit phase
- precommit phase
- render phase
I found this : http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/
I'm not sure if "mounting", "updating" and "unmounting" are phases or somethings else. Can it be the case that phases are: commit, precommit and render. And "mouting, updating and unmounting" are events or stages ?
Any clues?
The "render phase" and "commit phase" are descriptions of the internal process that react goes through to update your page. While it can be useful to understand what's going on in these, the only place you can interact with it is through the various lifecycle hooks, such as componentDidMount, componentDidUpdate, and componentWillUnmount, so those are the things i would recommend you focus your research on.
When it's time to render the page (usually caused by calling this.setState somewhere), react goes through a series of steps in order to update the webpage:
The first group of steps are collectively called the "render phase". In the render phase, react is creating the Virtual DOM. In other words, it's determining what the page is supposed to look like, without actually changing the page. In the simplest form (where we're not skipping any renders with things like react.memo or shouldComponentUpdate), react calls render on the topmost component, and finds out what it returned, and then for each of its children it calls render on those as well until it knows what the whole page should look like.
The second group of steps are called the "commit phase". Now that it knows what the page should look like, it needs to update the actual DOM to match the Virtual DOM. To do this, it compares the current virtual DOM that it got from the render phase with the virtual DOM it got the last time it rendered, and figures out the minimum set of updates in order to make the page look like that.
And now the rendering is done and the page has been updated. During this process it's possible that some components got created for the first time (ie, "mounted"), or they got their props changed (ie, "updated"), or they were removed entirely ("unmounted"). Components that had this happen to them will have their componentDidMount, componentDidUpdate and componentWillUnmount functions called as appropriate.
Render phase: Is used to calculate changes, and may be aborted if the user wants to. If this phase is aborted the DOM isn’t updated.
Pre-commit phase: Is a period where you can read changes made to the VDOM, before they are applied to the actual DOM.
Commit phase: Here the changes are applied and any side effects are triggered.
Mounting: Runs once when the component is created.
Updating: Runs each time a change is made to the component.
Unmounting: Runs once when the component is about to be destroyed.
Have a look at this article for details
https://medium.com/#vmarchesin/the-react-lifecycle-step-by-step-47c0db0bfe73#:~:text=Pre%2Dcommit%20phase%3A%20Is%20a,any%20side%20effects%20are%20triggered.
I have a react.js app which loads data from an API displays a bunch of questions (textboxes, radiolist, checkboxes, etc). The user fills them in and submits all answers back to the API, which then send a new set of questions.
All these questions are in a single object, so I've created parent react.js component which holds the current set of questions in state. When the state changes it re-renders each question below. This works pretty much fine.
The problem is that sometimes the API displays the exact same question for twice in a row, but as this is held in state and react.js is clever enough to know it doesn't need to render a completely new component, because the old one will do (with a few small updates).
The problem is that if I select a radio button on the first one, based on the initial data stored in state of the child component, which was initially set within componentDidMount). But when the second question comes along, because its essentially the same component, the state remains. The constructor is not called again.
I think I should be using one of the other events, perhaps:
componentWillReceiveProps
componentWillMount
componentWillUpdate
but I can't figure out which one is the most consistent one.
I basically want to reset the selectedAnswer everytime the parent has received new data from the API and essentially re-render all child components (but react won't do that).
Edit
I wonder instead of trying to reset this via the internal lifecycle events, whether I can pass in a different set of props into the component, so it can decide whether to re-create or re-render in the usual way.
okay so to optimally do this lets suppose you api which returns the set of questions, it might contain some id associated with it. Using that id create a uniq key for every child component while rendering something like below
<Child key={`${data_id}_${index}`} />
This will ensure that for the same set they do not keep mounting again and again and will only mount if a new data set is fetched in which case data_id will change which would cause remounting of each and every child component
I'd encourage you to check out Redux. It makes managing state much easier. I'd contribute some code on here but I am not sure I actually understand the question. If you linked us to your Github, then I could probably answer this specific question.
Also, it seems like you don't really need to touch state. It sounds more life attaching an event and controlling state that way. For example, using onSubmit, you can make an API call (and whatever else) and then have another function to reset the form state afterwards. It would be pretty straight forward, especially if you are using then/catch Promises.
the documentation says
All React components must act like pure functions with respect to their props.
https://facebook.github.io/react/docs/components-and-props.html, but does not explain the real reason behind it, why is that?
A React component should be pure, this means the result of its render method should depend solely on the props and the state, and for the same properties and state render should give the same result.
If render is not pure, it means it can return different results for the same input, so React cannot tell which parts of the DOM need to be updated based on the changes to the component. This is critical as the performance of React depends of this. Why? That's a bit complex.
It is amazing to define the UI based on a state, and have the UI re-render itselfs every time any part of the state changes. But you can imagine doing a complete re-render of the entire DOM every time you change something would be painfully slow.
React solves this by checking the minimum ammount of changes needed o the DOM to reflect the new state. It knows what those changes are based on what properties and state each component receives, and can tell if it needs to update a component if any of its properties or state changed.
Take this tree as an example of a component hierarchy
Here we changed h to 8, so we also changed f because h is a child of f, and we also changed c because f is child of c and etcetera.
The key here is to think how React checks the component tree. It ill start at the root and see it changed. Then it'll check all the children and realize only c changed, so there is no need to check all the a and b branches. Then it'll check the c branch and realize only f changed so there is no need to check e and g. That operation is done on every component to calculate the minimum ammount of changes and also what needs to be updated.
If at any point you could mutate how a component is rendered it means React will need to check all of the branches and all of its children to know what changed because it can't rely on the state and the props to know when a branch changed and how. This would be painfully slow and make the whole React framework inviable.
I would say because of tracking the component state changes. If it isn't pure, it would cause side-effects every time it is executed. That way, would be very hard to know what has changed and furthermore how to react to these changes.
Pure functions, in other way, have the same output with the same input. Making it a lot easier to manage properties and track when something has changed, resulting a easier and predictable way to react to the change.
If they weren't pure functions in relation to their props then it would be violating the entire heirarchy/delegation structure that react provides and relies on.
Lets say you have two components, component A and Component B, and Component A is the parent to Component B. Component A has its own state based on some sort of data. When you pass a part of its state down as a prop to component B, you are establishing a contract between the two components that component B will delegate to component A to get the value of said prop.
This is in a sense a contract between the two components and the only way the contract isn't violated is that component B doesn't directly alter or change the passed down prop. That is what being a pure function means, that it doesn't mutate the prop directly. Of course you can clone the prop and then change it however you want that isn't a breaking of contract since at that point they aren't referencing the same values. But if you do mutate props directly you will also be mutating the parent component value. This can cause unintended side effects as well as cause issues with the react shadow dom differencing algorithm.
Here is that explained from the official react docs
https://facebook.github.io/react/blog/2015/02/24/streamlining-react-elements.html#problem-mutating-props-you-dont-own
You will discoverer "Why" understanding Reconciliation algorithm React uses for rendering.
Here you have all the information needed to understand what you want.
Part of that is well explained in Marco Scabbiolo's answer, but If you want to understand the way React works I strongly recommend you to read the post I've suggested.
Posting the answer here would be too much for a post and unnecesary because It has already explained by React Team. That's why I prefer giving you the source directly.