Does render get called any time "setState" is called in reactjs?
By default, yes, React will call the render
method (in a class component) or re-run the component function (in a function component) every time you call setState
. When you invoke setState
, React schedules a re-render for that component and potentially its descendants. However, React applies optimizations and may batch multiple state updates together. Below, we’ll explore some nuances around when and how render
gets called in both class and function components.
1. Class Components
The Default Behavior
In a class component, any call to this.setState()
marks the component for re-render. React queues up these state changes, and on the next render cycle, React will call render()
for that component.
class MyComponent extends React.Component { state = { count: 0 }; increment = () => { this.setState((prevState) => ({ count: prevState.count + 1 })); }; render() { console.log('Render called!'); return ( <button onClick={this.increment}> Count: {this.state.count} </button> ); } }
Clicking the button repeatedly will call setState
, which in turn causes render()
to be called each time—though React may batch these updates to reduce re-renders if they happen very quickly.
Conditional Rendering via shouldComponentUpdate
If you implement the shouldComponentUpdate(nextProps, nextState)
lifecycle method (or PureComponent
, or memoization techniques), you can override the default behavior. This allows you to return false
and prevent an update cycle—thereby skipping the render()
call—even if setState
was invoked.
shouldComponentUpdate(nextProps, nextState) { // Return true or false based on comparison of current vs. next props/state return nextState.count !== this.state.count; }
2. Function Components with Hooks
Re-render on State Updates
In function components, using useState
or other hooks also triggers a re-render whenever state changes:
function MyFunctionalComponent() { const [count, setCount] = React.useState(0); const increment = () => setCount((prev) => prev + 1); console.log('Render called!'); return ( <button onClick={increment}> Count: {count} </button> ); }
Each time you call setCount
, React marks your component for re-render, and the entire function runs again (including its return
JSX).
Memoization with React.memo
To skip unnecessary renders in function components, you can wrap them in React.memo
. This higher-order component does a shallow comparison of props. If props don’t change, React can skip re-rendering:
const MyMemoizedComponent = React.memo(function MyMemo({ value }) { console.log('Render called!'); return <div>{value}</div>; });
However, internal state updates within a memoized component will still cause re-renders—React.memo
only memoizes with respect to props. If you want to skip re-renders based on state, you’ll need other optimizations.
3. Batching of State Updates
In modern React, multiple setState
or useState
calls within the same event loop may get batched, resulting in fewer actual re-renders. This means React can combine multiple state changes before calling render()
, improving performance. However, each batch still leads to at least one re-render if the state changes.
4. When Render Might Not Be Called
shouldComponentUpdate
returning false: In class components, ifshouldComponentUpdate()
returns false, the re-render is skipped.React.PureComponent
: Internally uses shallow props and state comparison. If nothing changes,render()
is not called.React.memo
: For function components, if props are unchanged (and there’s no internal state change), React can skip re-rendering.
Best Practices and Tips
- Avoid Unnecessary Re-renders
- Use memoization (
React.memo
,useMemo
, oruseCallback
) or pure components to prevent expensive re-renders.
- Use memoization (
- Don’t Over-optimize Too Early
- Overusing memoization can lead to complexity. Optimize only where performance issues are real.
- Rely on React’s Batching
- State updates within the same event loop can be batched, minimizing performance overhead.
Conclusion
In most cases, calling setState
(or a state setter in function components) triggers a re-render. This is the default React behavior, ensuring your UI stays in sync with your state. You can override this behavior using lifecycle methods like shouldComponentUpdate
, PureComponent
, or wrapping function components in React.memo
if you want to skip updates. Regardless, React’s reconciliation process, combined with batching, helps ensure that your components render efficiently under typical use cases.