2
votes

I'm getting a warning message on my app and I've tried lots of things to remove it, without success. Error Message:

React Hook useEffect has a missing dependency: 'updateUserData'. Either include it or remove the dependency array react-hooks/exhaustive-deps

I don't want to exclude that with a comment to avoid the issue, but I want to fix it in a "best practices" way.

I want to call that updater function and get my component updated, so I can share that context in other components.

So... what i'm doing wrong? (any code review about the rest is very welcomed!)

Thanks a million!

If I add [] as the 2nd parameter of useEffect I get the warning, and removing it I get an inifinite loop.

Also adding [updateuserData] gets an infinite loop.

import React, { useState } from "react";
import UserContext from "./UserContext";


interface iProps {
    children: React.ReactNode
}

const UserProvider: React.FC<iProps> = (props) => {
    // practice details
    const [userState, setUserState] = useState({
        id'',
        name: ''
    });

    // practice skills
    const [userProfileState, setuserProfileState] = useState([]);

    // user selection
    const [userQuestionsState, setuserQuestionsState] = useState({});


    return (
        <UserContext.Provider value={{
            data: {
                user: userState,
                userProfile: userProfileState,
                questions: userQuestionsState
            },
            updateuserData: (id : string) => {
                 // call 3 services with axios in parallel
                 // update state of the 3 hooks
            }
        }}
        >
            {props.children}
        </UserContext.Provider>
    );
};

export default UserProvider;
const UserPage: React.FC<ComponentProps> = (props) => {


    const {data : {user, profile, questions}, updateUserData}: any = useContext(UserContext);

    useEffect(() => {
        // update information
        updateUserData("abcId")
    }, []);



    return <div>...</div>

}

The idea is the following:

  • I have a context

  • I created provider for that content

  • that context exposes the data and an updater function

  • I use that provider in a component with the useEffect hook and I get the warning

  • I want to keep all the logic about fetching and updating the context inside the provider, so I don't replicate it all over the other components that are needing it.

1
Possible duplicate of Infinite loop React hooks - Pierre V.
When do you want userPage to call updateUserData? Just once on mount? If so, then an empty array is the correct second param, and you'll use an eslint-ignore to dismiss the lint warning. - Nicholas Tower
I want to run it once, when it get's mounted and also when the route changes (i.e.: when the props.match.params.userId changes) - Ricardo Daniel
thanks @WillJenkins ! sorry for the delay! - Ricardo Daniel

1 Answers

2
votes

Firstly, the infinite loop is caused by the fact that your context is updating, which is causing your component to be re-rendered, which is updating your context, which is causing your component to be re-rendered. Adding the dependency should prevent this loop, but in your case it isn't because when your context updates, a brand new updateuserData is being provided, so the ref equality check detects a change and triggers an update when you don't want it to.

One solution would be to change how you create updateUserState in your UserProvider, using e.g. useCallback to pass the same function unless one of the dependencies changes:

const UserProvider: React.FC<iProps> = (props) => {
  // practice details
  const [userState, setUserState] = useState({
      id'',
      name: ''
  });

  // practice skills
  const [userProfileState, setuserProfileState] = useState([]);

  // user selection
  const [userQuestionsState, setuserQuestionsState] = useState({});
  const updateuserData = useCallback(id=>{
    // call your services
  }, [userState, userProfileState, userQuestionsState])

  return (
      <UserContext.Provider value={{
          data: {
              user: userState,
              userProfile: userProfileState,
              questions: userQuestionsState
          },
          updateuserData
      }}
      >
          {props.children}
      </UserContext.Provider>
  );
};