ExtraSun
ExtraSun

Reputation: 548

How to pass a value using `createContext` from parent to child's child component?

Instead of passing props from parent to child1(parent of child2) ->to child2, I want to use createContext and receive the value with useContext.
What I tried to do is not correct because and I'm getting an error **'booleanContext' is not defined**.

How can I pass the createContext state/value ?

App.js
CreatePass is a component inside SignUp

  const [signUpFirst, setIfSignUp] = useState(true);
  const booleanContext = createContext(setIfSignUp);
  
 return (
    <booleanContext.Provider value={setIfSignUp}>

   <div>
     </Switch>
   <Route exact path='/signup'>
          <SignUp homePage={exitSignUpPage} setUserNumber={setUserID} />
        </Route>
        <Route exact path='/home'>
          <Home userIDNumber={userID} setIfSignUp={setIfSignUp} />
        </Route>
      <CreatPass /> 
      </Switch>
     </div>
    </booleanContext.Provider>
  );

SignUp.js

  render() {
    return (
      <div className='signUp-div'>
        <Header />
        <Router history={history}>
          <div className='form-div'>
            <Redirect to='/signup/mobile' />
            <Switch>
              <Route exact path='/signup/mobile' component={MobileNum} />
              <Route exact path='/signup/idnumber'>
                <IdentNumber setPersonalID={this.props.setUserNumber} />
              </Route>
              <Route exact path='/signup/password'>
                <CreatePass />
              </Route>
            </Switch>
          </div>
        </Router>
      </div>
    );
  }

CreatePass.js //'booleanContext' is not defined no-undef

const CreatePass = () => {
  const changeBooleanValue = useContext(booleanContext);

  const handleClickButton = () => {
      changeBooleanValue(true);
  };

  return (
    <div className='form-div'>
  <button onClick={handleClickButton}>Click</button>
    </div>
  );
};
export default CreatePass;

Edit - Update:

This solution is not good it's the same value as I did above, booleanContext is undefined -

export const booleanContext = createContext(); // default value is undefiend
...
const App = () => 
     return(
     <booleanContext.Provider value={setIfSignUp}>
      <CreatPass />        
     </booleanContext.Provider>
      )
}
export default App;

Will be glad for explanations

Upvotes: 0

Views: 1546

Answers (4)

Vinit S
Vinit S

Reputation: 422

Code looks ok. You can fix the default value error when exporting the context with an empty object {}.

export const booleanContext = createContext({}); 
export default function App() {
    ...
    return (
     <booleanContext.Provider value={setIfSignUp}>
         ...
     </booleanContext.Provider>
    )
}
 

and import it CreatePass.js

import React, { useContext } from "react";
import { booleanContext } from "./App";

const CreatePass = () => {
     const changeBooleanValue = useContext(booleanContext);
     ...
}

Upvotes: 0

Borris Wiria
Borris Wiria

Reputation: 476

for context provider and consumer, usually I create 1 hook for it like useBoolean.tsx that return BooleanProvider component that you can put inside your parent and useBoolean function that you can import inside your child component.

Basically any global function should wrap all its children inside its Provider.

So, if you want <CreatePass/> to access the value from the provider, it needs to be a children of its Provider

<BooleanProvider>
  <CreatePass/>
</BooleanProvider>

useBoolean.tsx will have something like this

// useBoolean.tsx
const BooleanContext = createContext()

export const BooleanProvider = ({ children }) => {
  const [signUpFirst, setIfSignUp] = useState(true)

  return (
    <BooleanContext.Provider value={{ signUpFirst, setIfSignUp }}>
      {children}
    </BooleanContext.Provider>
  )
}

export const useBoolean = () => {
  const context = useContext(BooleanContext)
  if (context === undefined) {
    throw new Error(`${useBoolean.name} must be within ${BooleanProvider.name}`)
  }
  return context
}

Parent component will be like usual

// Parent component
import { BooleanProvider } from 'hooks/useBoolean'

const Parent = () => (
  <BooleanProvider>
    <Child1 />
  </BooleanProvider>
)

Child1 will have Child2 and Child2 will use the useBoolean function we created

// Child1 component
const Child1 = () => (
  <div>
    <Child2 />
  </div>
)

// Child2 component
import { useBoolean } from 'hooks/useBoolean'

const Child2 = () => {
  const { setIfSignUp } = useBoolean()

  return <div></div>
}

Hope this helps clarify something for you. I am just trying to explain my understanding here on using the react context api and my way of doing it as well.

I tried to create hooks function like this for easier code management - it helps me understand what this context does directly with hooks naming convention. The hook function throws error too when it is not being used inside the Provider :D. Cheers 🙏!

Upvotes: 6

Arťom Pozdnyakov
Arťom Pozdnyakov

Reputation: 617

Move "const booleanContext = createContext(setIfSignUp);" Outside of the component, you dont want to change context reference every render. Also export it for other components.

export const booleanContext = createContext(); // default value is undefiend
...
const App = () => ...

export default App;

Then in CreatePass, you should import context (used named export, so import would be like this:

import { booleanContext } from '..somePath../App'

Now it should work.

EDIT:

Works as expected https://codesandbox.io/s/createcontexttest-0qvvm?file=/src/App.js

EDIT 2

<App>
  <CreatePass /> // there is value undefined
  <Context.Provider value={'something'}>
    <CreatePass /> // value is defined
    <SignUp>
       <CreatePass /> // also defined
    </SignUp>
  </Context.Provider>
  <div>
    <CreatePass /> // undefined
  </div>
</App>

Upvotes: 1

Abbasihsn
Abbasihsn

Reputation: 2171

first, create a custom component for your context provider:

import { createContext } from "react";

const CustomContext = createContext(["green", () => {}]);

export default CustomContext;

then wrap all your components using it in for example App.js:

<CustomContext.Provider value={options}>
  […]
</CustomContext.Provider>

and then you can use it as follows:

import CustomContext from "./CustomContext";

// top of SearchParams function body
const [options] = useContext(CustomContext);

Upvotes: -1

Related Questions