0

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

ExtraSun
  • 528
  • 2
  • 11
  • 31

4 Answers4

6

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 !

Borris Wiria
  • 466
  • 4
  • 8
1

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>
  • I already tried that, in `CreatePass ` it is `undefined`. booleanContext / the name I gave it - `changeBooleanValue` is `undefined`. not a good solution. – ExtraSun Jul 21 '21 at 08:43
  • I tried it in sandbox (link in edit) and it works as expected, maybe try "debugger;", if all values are passed ok. – Arťom Pozdnyakov Jul 21 '21 at 10:53
  • Your CodeSandbox link is an empty project, please check. – ExtraSun Jul 21 '21 at 11:00
  • https://codesandbox.io/s/createcontexttest-0qvvm?file=/src/App.js Tried to rename it, try now – Arťom Pozdnyakov Jul 21 '21 at 11:12
  • That because `CreatePass` is not inside `SignUp` component. I changed it in your codesandbox and got this error - `changeBooleanValue is not a function`. App.js - ```return (

    Hello CodeSandbox, value: {"" + signUpFirst}

    );``` And fixed `SignUp` component to be the parent of `Createpass`
    – ExtraSun Jul 21 '21 at 13:52
  • In this way of yours I can just pass props to `CreatePass` but wanted better way with - `createContext` – ExtraSun Jul 21 '21 at 13:54
  • Not sure why the downvote. This answer is correct. Your original error was simply because, as it said, `changeBooleanValue` was not defined in that file. You need to export it from somewhere and import in `CreatePass`. This has nothing at all to do with React. – Eric Haynes Jul 21 '21 at 15:44
  • Also components, that want to useContext value should be inside provider (as a child) - EDIT 2 – Arťom Pozdnyakov Jul 21 '21 at 15:53
  • It can be sometimes confusing, in that case i would recommend trying redux - you wouldnt need contexts, instead, dispatch actions from anywhere and redux updates only components, that changed. – Arťom Pozdnyakov Jul 21 '21 at 16:01
0

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);
     ...
}
Vinit S
  • 256
  • 3
  • 9
-1

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);
Abbasihsn
  • 2,075
  • 1
  • 7
  • 17
  • 1
    I tried that but I'm getting component `createPass` over other components in a one page, and if I ignore it (and passing all the process in the sign-up) I'm getting an error - `TypeError: changeBooleanValue is not a function`. – ExtraSun Jul 18 '21 at 14:30
  • 1
    I don't need a custom component in my App.js. because the - `const [signUpFirst, setIfSignUp] = useState(true);` is used inside the App.js – ExtraSun Jul 18 '21 at 14:51
  • if you mean `const changeBooleanValue = useContext(booleanContext);` section, absolutely its wrong! u should use `const [_, changeBooleanValue] = useContext(booleanContext);` instead. – Abbasihsn Jul 18 '21 at 15:00
  • 1
    I don't get it - `changeBooleanValue ` is the name that choose to give it at `CreatePass` component. Your code example is not as mine. – ExtraSun Jul 18 '21 at 15:03
  • yous said that you encounter with `TypeError: changeBooleanValue is not a function` error. it is due to the fact that`useState` returns the current state and also the second parameter is setFunction for that variable. – Abbasihsn Jul 18 '21 at 15:08
  • 1
    I'm passing only the setState - `setIfSignUp` with the Provider, did you see that? – ExtraSun Jul 18 '21 at 15:09