skip to Main Content

UseCallback(), are function paramaters always added ot the dependency array in default? whereas variables used directly wihtin the function’s body should only be added if I am sure they would be updated?

const User = ({}) => { 
 const [state, setState] = useState(1); 
 const randomVariable = 1;
 
 const handle = useCallback((state) => { 
 const User = setState(state + randomVariable) 
 }, [state]); 
 return ( )
})
  • Should both "state" and "randomVariable" be added to its dependency array?
  • will "state" always be ‘automatically added’ (by the compiler?) to the dependency array because it’s in the function’s arguments?
  • Whereas "randomVariable" has to be manually added to the dependency array (by me) depending on whether I plan to have "randomVariable" update frequently?

2

Answers


  1. Any variable (or similar) that your callback function closes over should be in the dependency array, since if they aren’t, an old version of the callback function closing over a previous variable (or similar) will be reused, causing bugs.

    • state – In your example, state isn’t something the function closes over. it’s a parameter to the function. (It has the same name as a variable the function would close over, but because you’ve declared it as a function parameter, that takes precedence — shadows — the outer declaration.) Since that parameter is something your callback receives when called, rather than closing over, it doesn’t belong in the dependency array.
    • randomVariable – Your callback does close over randomVariable, so it needs to be in the dependency array so you’re getting an up-to-date version of your callback when it changes, rather than continuing to use a stale version of your callback using a stale version of the variable.

    So:

    const User = ({}) => { 
        const [state, setState] = useState(); 
        const randomVariable = /*...presumably something here other than just 0...*/;
        
        const handle = useCallback((state) => { 
            const User = setState(state + randomVariable) 
        }, [randomVariable]); 
        return /*...*/;
    });
    

    If state weren’t a parameter to the callback and you wanted to use the one the function closes over, it would also need to be in the dependency list, but your function doesn’t seem at first glance to need to use the state state member.

    You may find my answer here handy, it goes into more general detail on useCallback.

    Login or Signup to reply.
  2. To remove a dependency, prove that it’s not a dependency

    Notice that you can’t “choose” the dependencies of your Effect. Every
    reactive
    value

    used by your Effect’s code must be declared in your dependency list.
    The dependency list is determined by the surrounding code:

    const serverUrl = 'https://localhost:1234';
    
    function ChatRoom({ roomId }) { // This is a reactive value
      useEffect(() => {
        const connection = createConnection(serverUrl, roomId); // This Effect reads that reactive value
        connection.connect();
        return () => connection.disconnect();
      }, [roomId]); // ✅ So you must specify that reactive value as a dependency of your Effect
      // ...
    }
    

    Reactive values include props and all variables and functions declared
    directly inside of your component. Since roomId is a reactive value,
    you can’t remove it from the dependency list. The linter wouldn’t
    allow it:

    const serverUrl = 'https://localhost:1234';
    
    function ChatRoom({ roomId }) {
      useEffect(() => {
        const connection = createConnection(serverUrl, roomId);
        connection.connect();
        return () => connection.disconnect();
      }, []); // 🔴 React Hook useEffect has a missing dependency: 'roomId'
      // ...
    }
    

    And the linter would be right! Since roomId may change over time, this
    would introduce a bug in your code.

    To remove a dependency, “prove” to the linter that it doesn’t need to
    be a dependency. For example, you can move roomId out of your
    component to prove that it’s not reactive and won’t change on
    re-renders:

    const serverUrl = 'https://localhost:1234';
    const roomId = 'music'; // ✅ Not a reactive value anymore
    
    function ChatRoom() {
      useEffect(() => {
        const connection = createConnection(serverUrl, roomId);
        connection.connect();
        return () => connection.disconnect();
      }, []); // ✅ All dependencies declared
      // ...
    }
    

    (source: react.dev docs)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search