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:

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?
useEffect - is asynchronous function! And you put yours condition in synchronous part of component. Off course synchronous part runs before asynchronous.
Move condition to useEffect
useEffect(() => {
if (personIdentId !== prevPersonIdentId.current) {
prevPersonIdentId.current = personIdentId;
console.log(
"Use effect",
personIdentId,
prevPersonIdentId.current,
counter.current++
);
setSuggestions([]);
}
});
It could be read as: When mine component updates we check property personIdentId for changes and if yes we update ref to it's value and run some functions
It looks like this is what's happening:
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.props.personId now changes, so you enter the if.setSuggestions([]) is called, triggering a re-render.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] );
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With