I'm using react-router-redux and have nested connect()ed components. This seems to work fine, except that my nested components are re-rendering when state changes.
Probs:
Root have 5 children:
All components are re-rendering if there is any state changes in any one of the children because all components are connect()ed.
How can I render only the required children alone?
(is there any way to using connectAdvanced life cycle method for resolve this probs?
To prevent the nested children from being re-rendered every time your state changes in the parent component you should use shouldComponentUpdate life cycle.
shouldComponentUpdate takes in 2 parameters shouldComponentUpdate(nextProps, nextState)
So anywhere you want to stop re rendering you should return false. As per the docs "Returning false does not prevent child components from re-rendering when their state changes."
ShouldComponentUpdate Docs
Related
I'm new to react. I'm going through their docs to understand how react works. So it was mentioned that when state/props/setState() changes/called, react rerenders the entire component.
Also, I read that react elements are immutable and they are rendered only when there is a change. So when react tries to render a component it actually traverses through all the elements checks for differences and renders only those elements whose data is changed. It won't simply re-render the entire component.
Am I right regarding this? Or is my understanding wrong?
I read that React elements are immutable and they are rendered only when there is a change.
Saying that React elements are immutable is not true, you need to treat them as immutable, especially component's state and props.
So when React tries to render a component it actually traverses through all the elements checks for differences and renders only those elements whose data is changed.
The default behaviour is to render all sub tree when the parent rerendered by calling setState (which triggers Reconciliation on component's sub tree).
So saying it will render components on "data change" is not true, they will rerender anyway by default, even if the "data" didn't change.
On saying "data is changed" we mean on props change (shallow comparison by default, use memoization to change it).
We can use key prop to help with the reconciliation process.
You are right, react re-renders the component when props or state changes.
That being said, when a child component received new props, react does not check if the props have changed when you use React.Component, it just re-renders even if you pass same props again.
In order to make components render only if they receive different props you can use React.PureComponent in case of class components or you can wrap the component with React.memo() in case of functional components.
I believe a clearer way to summarize when React components re-render would be:
React components re-render when, and only when:
Their state changes (via setState() or useState())
They are passed new props;
Their parent component re-renders.
Caveats:
You must update state correctly for the component to re-render, i.e. via setState() or useState(). If state changes via other, "illegal" means, such as directly accessing state, React won't notice, and won't re-render the component.
React props are read-only, so when we say "when a component's props change," we really mean when the component is passed props with changed values. The props should not be mutated within the component.
If you use useMemo() or React.memo(), then a child component will only re-render when the parent component re-renders if the props it receives have changed.
It's important to distinguish between re-rendering the virtual DOM and updating the actual DOM. Just because a component re-renders doesn't mean it's updated the DOM. When a component re-renders, React compares the new version to the previous, and only updates the actual DOM if something has changed 1, 2.
Nothing has made this clearer for me than this cheat sheet by A. Sidorenko.
Edit:
Essentially yes any state change will trigger a re-render. This includes the component where the state change was initiated and all its children. For instance, if your composition is:
A > B > C
If the state for A is updated then A, B, and C will get re-rendered. There are ways to prevent re-rendering subcomponents (e.g. memo, useMemo) so I point you the cheat sheet referred to above for the complete details.
I know React has a life cycle method called shouldComponentUpdate, Which by default return true and that's how the component decides to update
But How does that life cycle method gets called, When a state or props change for that component. What actually happens when we receive new props or state? When We connect a component to redux state and mapStateToProps, Are we checking for a change in values inside the component? If not, When We are looking for a change in state or props?
when the props or state changes, how the life cycle methods are called?. Do we have a listener that calls these methods when the props or state changes?
You should look at lifecycles of both, how they perform and in what order each method gets called. Looking at react lifecycle image bellow you can see the difference between componentWillMount and componentDidMount and others like componentDidUpdate, componentWillUpdate and so on...
Also you should reason when to use each method
To update state you call this.setState() which tells react that something has changed and it will re-render component tree. If you use this.state.data = something react won't trigger render(). Now to update props, you need to understand how render() actually works. This answer is summarized from existing anwser already:
Every time render() is called react will create a new virtual DOM
where the root node is the component whose render function is called.
The render() function is called when either the state or the props of
a component or any of its children change. The render() function
destroys all of the old virtual DOM nodes starting from the root and
creates a brand new virtual DOM.
In order to make sure the re-rendering of components is smooth and
efficient React uses the Diffing Algorithm to reduce the time it takes
to create a new tree to a time complexity of O(n), usually time
complexity for copying trees is > O(n^2). The way it accomplishes this
is by using the "key" attribute on each of the elements in the DOM.
React knows that instead of creating each element from scratch it can
check the "key" attribute on each node in the DOM. This is why you get
a warning if you don't set the "key" attribute of each element, React
uses the keys to vastly increase its rendering speed.
React Lifecycle
Redux Lifecycle
If you use redux library, may be, your component does not re-render after your props changes. Checkout this issue to resolve the props changes problem with componentWillReceiveProps
Suppose that in a react component, two siblings are rendered conditionally, meaning that one will get unmounted when the other gets rendered. In this scenario, is it guaranteed that componentDidMount method of the rendered component gets executed before other’s componentWillUnmount?
Are there any hooks fired off when one of the components children is removed (not rendered due to conditional) and then added back again? The change happens due to state update somewhere above the component tree, but I would like to intercept it somehow on half way up.
For some reason I had an impression that componentDidUpdate should fire in such case, but now I see that it only goes off when update happens to the components state or the state of one of its children...?
Each component has several “lifecycle methods” that you can override to run code at particular times in the process.
The three lifecycle methods are mounting, updating and unmounting.
Updating
An update can be caused by changes to props or state. These methods are called when a component is being re-rendered
So when a child component is not rendered it doesn't fall in any of these categories, ie mounting, unmounting or updating. Lifecycle method exists for components and any change that happens in the child components does not affect the parent component lifecycle methods in any way.
For updating to happen for a particular component, as mentioned above a change in state or props of that particular component has to happen
Read The Component Lifecycle from react docs.
I created a simple react app and checked the app for re-renders with why-did-you-update library and it shows unnecessary re-renders and how to prevent these re-renders?
Components will get re-rendered if their props change, or if their parent has been re-rendered. It's possible that you have update the props or state of a parent component. React provides a lifecycle function called shouldComponentUpdate to deal with unnecessary renders. It is quicker and easier to implement if you use immutable data for your props since you can simply do an equality check between new props and old props to see if there was any change. See https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate and https://facebook.github.io/react/docs/pure-render-mixin.html