Search code examples
reactjstypescriptreact-hooksuse-effectsetstate

setState inside useEffect or useCallback, dependency issue


I'm trying to remove console warnings from my code, but I'm confused about how to solve this dependency issue. I have a useEffect hook, that calls a method, removeMessage, which is defined inside my component. I get a warning that this should be in the useEffect dependency array, but if I do that, I create an infinite loop, since the function reference is re-created when the component rerenders.

const Component = () => {
    const [list, setList] = useState();

    const removeMessage = (message: string) => {
        const list = list.filter(x => x.message !== message);
        setList(list);
    }

    useEffect(() => {
        ...
        removeMessage("test");
    });

So I read that I'm supposed to use the useCallback hook, to ensure the reference is not changed:

const removeMessage = useCallback((message: string) => {
    const list = list.filter(x => x.message !== message);
    setList(list);
}, [list]);

But, unless I provide my list as a dependency for that hook, I will get a similar warning. But if I do, I create yet another infinite loop.

This code, and usage of useEffect, is propably bad practice, but I don't know how to work around it, since my method removeMessage is dependent on the state to do its filtering.

Thank you.


Solution

  • I think this should work (using the setState function variant). That way you do not have a dependency on list (and it is also more correct in edge cases)

    const Component = () => {
      const [list, setList] = useState<Array<{ message: string }>>([]);
    
      const removeMessage = useCallback((message: string) => {
        setList(prev => prev.filter(x => x.message !== message));
      }, []);
    
      useEffect(() => {
        removeMessage('test');
      }, [removeMessage]);
    };