Why isn’t my React component re-rendering?
This article separates errors that are common to plain React, React and Redux, and React-Redux.
Plain React: this is the simplest error to make, but I’ve seen it happen many times.
- Are you manually reassigning state, using: `this.state = newState` instead of: `this.setState(newState)`?
- Though manually reassigning or mutating the state will seem to update the state, it will not trigger a re-render of the component, and it should never be done.
React with Redux: if you are using Redux, make sure that you are making the most of the Redux devTools! Before looking too much at your React component, make sure that the right actions are being dispatched and that the new store state is correct. If the store state is updating, but your component isn’t re-rendering, then look for these errors:
- Does your Redux store mutate state instead of returning a new state object that has a different pointer? React uses shallow equality to check for changes to the state, so mutating the state will not trigger re-rendering. Use Object.assign or Rest with Object properties to avoid this error.
A subset of this problem is: Nested Entities and Eager Loading with an ORM.
- If you are using an ORM on your backend that supports eager loading (like Sequelize or Active Record), and making AJAX requests for these resources and adding them to your redux store (with THUNKs), you are probably creating duplicate/nested entities on your Redux store — potentially without even realizing it. Any action that updates this field needs to both change the entity itself, and where it exists as a property on another model. Redux documentation suggests to keep models separate in our store just as they are separate in our database.
- If you want to use eager loading, make your action to update that data match cases on multiple reducers — one to update that data itself, and another to update wherever that model is eagerly loaded. However, this could end up causing unnecessary re-rendering.
- The Redux Docs recommend using the Normalizr library to create a normalized transformation the nested data before updating the store.
Using React-Redux library to subscribe to the store:
- The points above about shallow equality for state still apply, and we add another concern:
- If using React-Redux, does your mapStateToProps function send all of the relevant state down? If you aren’t subscribed to it with mapStateToProps, it won’t trigger a re-render.
Worst case scenario: If you really can‘t make your component re-render, you can always force an update using forceUpdate(), which will call the render function and all of the other lifecycle methods (except shouldComponentUpdate). This should generally be avoided, because React will trigger appropriate re-rendering if state and props are being managed correctly.