0

I am trying to refactor an app to use useContext but have hit a snag and cannot figure out what is happening.

Using the latest version of everything, running Next.js.

The way things are structured is that every page is wrapped in <Layout> and some pages are also wrapped in <Fund>, nested under <Layout>.

I have global context that is set in _app.js and passed to Layout where it is rendered. This works fine, the aTest context variable that I define in pages/_app.js renders on Layout and shows on all pages.

Then I have fund-specific context that is set in components/Fund.js and loaded in on pages/fund/index.js (and subsequent other pages).

This does not work. The anotherTest context variable that I define in /components/Fund.js is not showing in /pages/fund/index.js even though the return statement there is wrapped in the <Fund> component (which I assume should hold and pass on the context).

I think I have maybe got my child/parent order mixed up for the non-working scenario but by brain is fried. Any tips?

Stripped back, the basic code is:

/components/
   - UserContext.js
   - FundContext.js
   - Layout.js
   - Fund.js

/pages/
   - _app.js
   - index.js
   - /fund/
      - index.js

Both the /components/*Context.js files are the same bar the names declared in them:

import { createContext } from 'react';
const FundContext = createContext();
export default FundContext;

and

import { createContext } from 'react';
const UserContext = createContext();
export default UserContext;

In /pages/_app.js I am doing:

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

function MyApp({ Component, pageProps }) {
   ...
   return (
      <UserContext.Provider value={{
         aTest: "This is a test"
    }}>
      <Component {...pageProps} />
    </UserContext.Provider>
   )
}

export default MyApp

In /components/Layout.js I am doing:

import React, { useState, useContext } from "react";
import UserContext from './UserContext';
const Layout = ({children}) => {    

   let {aTest} = useContext(UserContext);

   return (
      <main>
         <h1>{aTest}</h1>
         {children}
      </main>
    )
}

export default Layout

In /components/Fund.js I am doing:

import React, { useState, useContext } from "react";
import UserContext from './FundContext';
const Fund = ({children}) => {    

   return (
      <main>
         <h1>{aTest}</h1>
            <FundContext.Provider value={{ anotherTest: "Just another test" }}>
            {children}
         </FundContext.Provider>
      </main>
    )
}

export default Layout

In /pages/fund/index.js I am doing:

import React, { useState, useContext } from "react";
import FundContext from '../../components/FundContext';
...

export default function App () { 

   let {anotherTest} = useContext(FundContext);
   
   return (
      <Fund>
         {anotherTest}
      </Fund>
   )
}

1 Answer 1

1

Your useContext hook is called in the global scope on /pages/fund/index.js. Moving the hook to the scope of the component should fix the issue.

import React, { useState, useContext } from "react";
import FundContext from '../../components/FundContext';
...

export default function App () {
   let {anotherTest} = useContext(FundContext);
 
   return (
      <Fund>
         {anotherTest}
      </Fund>
   )

Also, I do not see a FundContext.Provider anywhere in the provided code, which means that calls to useContext(FundContext) will not work as intended. If it is not present, make sure a wrap the consumers of FundContext with it.

EDIT (OP updated the question):

useContext(FundContext) is being used above FundContext.Provider in the component tree.

  |_App (useContext(FundContext))
     |_Fund
         |_FundContext.Provider
                    |_{anotherTest}

Consider moving FundContext.Provider above the App component, or pass a component similar to the following one as a child to Fund:

const AnotherTest = () => {
  let {anotherTest} = useContext(FundContext);

  return (
      <>
         {anotherTest}
      </>
   )
}

/pages/fund/index.js:

import React, { useState, useContext } from "react";
import FundContext from '../../components/FundContext';
...
export default function App () {
   return (
      <Fund>
         <AnotherTest />
      </Fund>
   )
}
Sign up to request clarification or add additional context in comments.

4 Comments

Sorry some typos on my part, I have updated fund.js now to include the FundContext.Provider. I also moved the useContext to inside the component and it's not fixed it. I tried console logging useContext(fundContext) and its returns undefined.
You are using the useContext hook above the provider in the component tree. I will update the answer to reflect your changes
Argh sorry! fund is not even be using the useContext hook, only establishing the data for the enew context FundContext, which is then to be passed to its children /pages/fund/index.js. The example code should be correct now (still not working)
Answer should be accurate now

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.