React.memo issue with Redux

816 Views Asked by At

I have two components.

function Parent(props){

  const handleClick = () => {
   console.log(props.stateA);
  };

  return <div><Child text={stateB} handleClick={handleClick} /></div>
}

const mapStateToProps = (state) => {
  return {
    stateA: state.stateA // stateA will be changed somewhere else
    stateB: state.stateB
  }
};

export default connect(mapStateToProps)(Parent);
function Child(props) {
   return <div onClick={props.handleClick}>{props.text}</div>
}

export default React.memo(Child,(prev, next) => {
   return prev.text === next.text
});

My problem is when stateA is changed somewhere, clicking on Child will log the previous stateA. I can't access the latest stateA.

You can see, I don't want to Child re-render when stateA changes,it should re-render only when stateB changed. But I want to access the latest stateA in Parent when clicking on Child.

Is there any method to solve this problem?

4

There are 4 best solutions below

1
On

If the Parent component is a functional component then you can use like this

 const [valueA, setValueA] = useState('')
 useEffect(() => {
      setValueA(props.stateA)
 },[props.stateA])

 console.log(valueA) // latest Value of stateA
 return <div><Child text={stateB} handleClick={handleClick} /></div>

I hope it'll work for you.

4
On

You should be able to access props.stateA no problem

const handleClick = () => {
   console.log(props.stateA);
};

because you accessing parent's props in handleClick. So if props.stateA is stale then the logical conclusion is the parent doesn't receive the latest props. Can we see how you update props/state?

1
On

You can keep a ref to stateA so it is what is logged when you call handleClick. useRef ensures that the last value is used.

function Parent(props){
  const stateARef = useRef(props.stateA);

  useEffect(() => {
    stateARef.current = props.stateA;
  }, [props.stateA])

  const handleClick = () => {
   console.log(stateARef.current);
  };

  return <div><Child text={stateB} handleClick={handleClick} /></div>
}
0
On

The problem you are experiencing has nothing to do with Redux.

The Parent component passes 2 props to the child: the text which is changed when needed and handleClick which is changed each render of the Parent component - a new function is created each time.

But the React.memo is checking only the text prop, so the child receives a stale handleClick quite often.

The correct solution is to wrap the handleClick with useCallback and check all props in React.memo (react does this by default).

function Parent(props){

  const handleClick = useCallback(() => {
   console.log(props.stateA);
  }, []);

  return <div><Child text={stateB} handleClick={handleClick} /></div>
}

const mapStateToProps = (state) => {
  return {
    stateA: state.stateA // stateA will be changed somewhere else
    stateB: state.stateB
  }
};

export default connect(mapStateToProps)(Parent);

function Child(props) {
   return <div onClick={props.handleClick}>{props.text}</div>
}

export default React.memo(Child);