Ricardo Daniel
Ricardo Daniel

Reputation: 441

React Hook useEffect dependency issue

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:

Upvotes: 2

Views: 4777

Answers (1)

Will Jenkins
Will Jenkins

Reputation: 9787

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>
  );
};

Upvotes: 2

Related Questions