Search code examples
reactjsreact-hookseslint

useEffect exhaustive-deps rule is confusing


I have found a few questions related to this on stackoverflow, but nothing that satisfies a use-case which I have very regularly while using useEffect. Let's say I have some code like this:

const ApiViewer = (props) => {
    const [result, setResult] = useState('')

    useEffect(async () => {
        setResult(await callApi(props.valueThatWillChangeButIOnlyCareAboutItsInitialValue))
    }, [])

    return <div>{result}</div>
} 

The exhaustive-deps rule will throw, asking me to put props.valueThatWillChangeButIOnlyCareAboutItsInitialValue in the dependency array. I don't want to do this as I only want the initial value. I may use that prop in a separate effect somewhere.

I can't think of another way to write this either.

I also have the problem that other people seem to have, i.e. using functions/etc that I know will never change. I don't want to add them to this array, seems very dumb.

Dan Abramov said that Usually disabling it is a mistake and will significantly bite you later. I've been using it this way for years and I've seen no issues until this rule started popping up in a new project.

Am I using React completely wrong?


Solution

  • Treating "exhaustive deps" as the true rule that it is will ensure components update as expected.

    If you want to ignore updates to a given prop you can clarify that by using a useRef. You won't get any warnings inside a useEffect because the base object returned from useRef never changes. Using an initial prefix will make this obvious to the next developer as well.

    const ApiViewer = (props) => {
        const [result, setResult] = useState('')
        const initialValueThatWillChangeRef = useRef(props.valueThatWillChange);
    
        useEffect(async () => {
            setResult(await callApi(initialValueThatWillChangeRef.current))
        }, [])
    
        return <div>{result}</div>
    } 
    

    You can construct examples where everything works as expected by ignoring the "exhaustive deps" rule, but you will eventually run into a nuanced case that breaks for reasons that are difficult to debug.