Read prev props: Too many renders

giorgim :

I want someone to confirm my intuition on below problem.

My goal was to keep track (similar to here) of props.personIdentId and when it changed, to call setSuggestions([]).

Here is code:

function Identification(props) {
    let [suggestions, setSuggestions] = useState([]);

    let prevPersonIdentId = useRef(null)
    let counter = useRef(0) // for logs

    // for accessing prev props
    useEffect(() => {
        prevPersonIdentId.current = props.personIdentId;
        console.log("Use effect", props.personIdentId, prevPersonIdentId.current, counter.current++)
    });


    // This props value has changed, act on it.
    if (props.personIdentId != prevPersonIdentId.current) {
        console.log("Props changed", props.personIdentId, prevPersonIdentId.current, counter.current++)

        setSuggestions([])
    }

But it was getting in an infinite loop as shown here:

enter image description here

My explanation why this happens is that: initially when it detects the prop has changed from null to 3, it calls setSuggestions which schedules a re-render, then next re-render comes, but previous scheduled useEffect didn't have time to run, hence the prevPersonIdentId.current didn't get updated, and it again enters and passes the if condition which checks if prop changed and so on. Hence infinite loop.

What confirms this intuition is that using this condition instead of old one, fixes the code:

 if (props.personIdentId != prevPersonIdentId.current) {
        prevPersonIdentId.current = props.personIdentId;
        setSuggestions([])
 }

Can someone confirm this or add more elaboration?

Will Jenkins :

It looks like this is what's happening:

  1. On the first pass, props.personId is undefined and prevPersonIdentId.current is null. Note that if (props.personIdentId != prevPersonIdentId.current) uses != so undefined is coerced to null and you don't enter the if.
  2. Another render occurs with the same conditions.
  3. props.personId now changes, so you enter the if.
  4. setSuggestions([]) is called, triggering a re-render.
  5. loop forever

Your useEffect is never invoked, because you keep updating your state and triggering re-renders before it has a chance to run.

If you want to respond to changes in the prop, rather than attempting to roll your own change-checking, you should just use useEffect with the value you want to respond to in a dependency array:

useEffect(() => {
       setSuggestions([])
 }, [props.personId] );

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=26235&siteId=1