2

I have a context that looks like this:

const peopleContextDefaultValue = {
  name: null,
  age: null,
  setName: null,
  setAge: null,
};
    ...

  const [name, setNameState] = useState();
  const [age, setAgeState] = useState();

  const setName = (payload) => {
    setNameState(payload);
  };

  const setAge = (payload) => {
    setAgeState(payload);
  };

  const value = {
    name,
    age,
    setName,
    setAge,
  };

  return (
    <>
      <PeopleContext.Provider value={value}>
        {children}
      </PeopleContext.Provider>
    </>
  );

And I'd like to set some default values off my .env, after the app loads for the first time. So I put this useEffect in _app.js:

function MyApp({ Component, pageProps }: AppProps) {
  const { setName, setAge } =
    usePeople();

  useEffect(() => {
    const effect = async () => {
      const name = process.env.NEXT_PUBLIC_NAME;
      const age = process.env.NEXT_PUBLIC_AGE;

      if (name) {
        setName(name)
      );
    

      if (age) {
        setAge(age)
      }
     };

    effect();
  }, []);

  return (
    <PeopleProvider>
      <Navbar />
      <Component {...pageProps} />
    </PeopleProvider>
  );
}

export default MyApp;

But, I keep getting this error:

setName is not a function

The problem seems to be that setName is staying with its default value from peopleContextDefaultValue, but I don't understand why. Does anyone understand this? Any idea how to fix/approach this?

Thanks a ton in advance for any help!!

1 Answer 1

1

Provider should be at the highest level of any components using its context, you are accessing context state, so you need to wrap <MyApp /> in it as well:

// For a normal React app, but won't work for Nextjs
<PeopleProvider>
  <MyApp />
</PeopleProvider>

In case of Nextjs, the highest level component is the _app.js file, so above won't work, since there aren't any higher level component than _app.js.

So I'd recommend move your current logic from _app.js file to index.js file, while keeping the provider code, and your existing code should work, otherwise, you can take a look at this answer.

Sign up to request clarification or add additional context in comments.

9 Comments

Thanks for answering! I tried to move it to index.js like you suggested, wrapping the Home component (return ( <PeopleProvider><div><Head>...</Head></div></PeopleProvider>)) (not letting me use code markup here for some reason). It's still getting the default values though... Am I doing something wrong?
Hi, you didn't keep the code when moving logic: <PeopleProvider><Navbar /><Component {...pageProps} /></PeopleProvider> <- this should stay, as it is providing the context for child component, I modified your code to make it more clearer to understand, please take a look
Since overriding variable is considered a bad practice, and there's no need to introduce another layer to setState function(unless you have a good reason to do so), like you defined setNameState and setName, but the setState function is already enough to mutate the name state.
On the createContext() bit, you actually don't have to provide a default value like so: createContext(defaultValue), it will consume the value from here: <PeopleContext.Provider value={value}>, you can refer to documentation on it.
Well, that seems like related to import error, you can research into it, or open another question, maybe others will take a look. Anyway, seems like you have solved this one, if you can accept my answer and upvote it, it'll be appreciated! As always, encourage other's question or answer by upvote is considered a positive behavior on Stackoverflow. Cheers!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.