Dimitri Kopriwa
Dimitri Kopriwa

Reputation: 14385

How to rerender a component in react-navigation when focus happen?

I am trying to useFocusEffect to rerender a component in my view when I focus the view.

I did:

const [theKey, setTheKey] = useState(0);

Then:

useFocusEffect(() => { setTheKey(theKey + 1) }, [theKey]);

And the jsx:

<SwipeListView key={theKey} /> 

It does not work well, I have the errror: Maximum update depth exceeded

Can someone share a way to rerender it?

I do not have this issue with react router.

Upvotes: 2

Views: 3188

Answers (2)

TylerC
TylerC

Reputation: 115

I also encountered issue with useFocusEffect. Either it triggers infinite loop / render, or it keeps a stale version of the function.

const [count, setCount] = useState(1);
const doSomething = useCallback(() => {
    console.log(count);
    setCount(count + 1);
}, [count]);

useFocusEffect(
    useCallback(() => {
        doSomething(); // Count will always be 1 (cached value)
    }, [doSomething])
);

useFocusEffect(
    useCallback(() => {
        doSomething(); // Latest count, but infinite loop due to doSomething() is recreated when count changes
    }, [doSomething])
);

Instead, can try with the combination of useIsFocus and usePrevious which works well with existing useEffect method.

import { useIsFocused } from "@react-navigation/native";
import { useEffect, useRef } from "react";

// usePrevious custom hook
function usePrevious(value) {
    const ref = useRef();
    useEffect(() => {
        ref.current = value;
    });
    return ref.current;
}

const isFocused = useIsFocused();
const prevIsFocused = usePrevious(isFocused);


useEffect(() => {
    if (!prevIsFocused && isFocused) {
        // Run your code here
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
}, [isFocused]);

Upvotes: 0

Dylan Kerler
Dylan Kerler

Reputation: 2187

Issue is here:

useFocusEffect(() => { setTheKey(theKey + 1) }, [theKey]);

Inside this function you update theKey. And each time theKey gets updated the effect gets called again. This results in an infinite loop.

There are 2 solutions:

Remove theKey dependency:

useFocusEffect(
    () => { setTheKey(theKey + 1) }, 
    ["replace with something else"]
);

Add a condition before updating the state:

useFocusEffect(
    () => { if ("some condition") setTheKey(theKey + 1) }, 
    [theKey]
);

This will prevent the infinite loop.

Upvotes: 1

Related Questions