Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I know you can tell React to skip an effect by passing an array as an optional second argument.

For example:

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes

But what if i want to control over the comparison? to add my own comparison logic.

I would expect something like React.memo that you can pass a function as a second argument.

what kind of comparison logic do you need. Effect is supposed to run when a value has changed. Any other kind of comparison can do as a if-else block in useEffect – Shubham Khatri Feb 6, 2019 at 11:04

In a comment above Gabriele Petrioli links to the React.memo documentation that explains how to implement shouldComponentUpdate. I was googling combinations of shouldComponentUpdate + useEffect + "react hooks", and this came up as the result. So after solving my problem with the linked documentation I thought I would bring the information here as well.

This is the old way of implementing shouldComponentUpdate:

class MyComponent extends React.Component{
  shouldComponentUpdate(nextProps){
    return nextProps.value !== this.props.value;
  render(){
    return (
     <div>{"My Component " + this.props.value}</div>

The New React Hooks way:

React.memo(function MyComponent (props) {
  return <div>{ "My Component " + props.value }</div>;

I know you were probably asking for more in your question, but for anyone coming from Google looking for how to implement shouldComponentUpdate using React Hooks, there you go.

The documentation is here: how-do-i-implement-shouldcomponentupdate

Adding to PAT-O-MATION's answer,
React.memo also accepts a second parameter, which is function which can be used to determine if a component should render or not.

if the function returns true then component won't re-render on change of that prop, conversely it updates when the return value is false

function SomeComp({prop1, prop2}) {
    return(
React.memo(SomeComp, (props, nextProps)=> {
    if(props.prop1 === nextProps.prop1) {
        // don't re-render/update
        return true

Note: Component would only re-render when the callback function returns false, so in the above case even if the prop2 value changes it won't re-render

Note: Returning true in case of React.memo means no re-render which is opposite of shouldComponentUpdate where true means that component should re-render. – Tal Aug 30, 2021 at 16:48

In addition to Avinash's answer. Important note for returning values:

shouldComponentUpdate() {
  // returns true by default
  // return false if you don't need re-render
export default React.memo(Component, (props, nextProps) => {
  if(props.prop1 === nextProps.prop1) {
    // return true if you don't need re-render

An alternative might be to use useRef to hold your data, and use useState ONLY to store the data you want to display. Sometimes this works better than the memo approach: I've had a case recently where React was still rendering needlessly when using React.memo, and it was messing up some PIXI display. The approach below fixed it for me... hopefully I did not do an anti-pattern :-)

const countRef = useRef(0);
const [countDisplay, setCountDisplay] = useState(0);
yourUpdateFunction = () => {
  // An example of function where count gets updated,
  // and which will affect the display only when the
  // counter is even...
  countRef.current = countRef.current + 1;
  if ((countRef.current % 2) === 0) setCountDisplay(countRef.current);
return (<p>{countDisplay}</p>);
                Shouldn't it be return (<p>{countDisplay}</p>);? I can't edit the post because there are too many pendings edits on Stack Overflow. Also, where is yourUpdateFunction being used?
– Adrian
                Feb 21 at 13:27
                You're absolutely right, error on my end. yourUpdateFunction is just any random function where something happens to the data you are displaying (could be an API call, a user input event, a timer etc). The point being that you're working on some data using useRef, which React's rendering logic won't be tracking. You decide when you want to actually modify your display by then changing the data stored in the useState hook.
– Will59
                Feb 21 at 13:46

Here is a custom hook which takes an updater function, and returns a value that changes only when the updater function returns true, which can be passed in the second argument to useEffect or useCallback or useMemo to force a re-render:

function useShouldRecalculate(shouldRecalculateFn) {
  const prevValueRef = useRef(0);
  if(shouldRecalculateFn()) {
    // If we need to recalculate, change the value we return
    prevValueRef.current += 1;
  } // else we return the same value as the previous render, which won't trigger a recalculation
  return prevValueRef.current;

For example, this will update the document title only when count is even:

const shouldUpdateTitle = useShouldRecalculate(
  () => count % 2 === 0
useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [shouldUpdateTitle]); // eslint-disable-line react-hooks/exhaustive-deps

Why you probably shouldn't do this

In most cases, I wouldn't recommend doing this.

Generally, there's going to be cleaner ways to accomplish the same task, using idiomatic hooks API. (The above example could have just put an if block around the line that updates the document's title.)

Perhaps more importantly, the deps argument isn't just about optimization, but about keeping closure values up-to-date, and avoiding bugs like:

const [count, setCount] = useState(0)
const increment = useCallback(() => {
    // Bug: `count` is always 0 here, due to incorrect use of the `deps` argument
    setCount(count + 1)
}, [])

This bug will be caught by the react-hooks/exhaustive-deps linter rule, but you'll have to disable that rule anywhere where you use custom logic to control execution.

Use custom memoization logic is likely to make your components more bug-prone and harder to reason about in general. So I'd consider this useShouldRecalculate hook something of a last resort.

Passing the optional second array argument kicks in the effect function if the property passed in the array changes - just like shouldComponentUpdate method in a class component would run when props passed to the component change. You can decide in the effect function based upon the value of the parameter - if you want to the effect to apply or not.

This is not what OP asked. The second useEffect argument only lets you control the effect execution, not rerenders. – Faisal Arshed Feb 22, 2020 at 7:54

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.