Как передать значение с помощью » createContext` от родителя к дочернему компоненту ребенка?

#reactjs #react-hooks #use-context #createcontext

Вопрос:

Вместо props того, чтобы переходить от родителя к ребенку 1(родителю ребенка 2) ->к ребенку 2, я хочу использовать > createContext и получить значение с useContext помощью .
То, что я пытался сделать, неправильно, потому что и я получаю ошибку **'booleanContext' is not defined **.

Как я могу передать createContext состояние/значение ?

App.js
CreatePass-это компонент внутри регистрации

   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;
 

Редактировать — Обновлять:

Это решение не очень хорошее, это то же значение, что и выше, booleanContext не определено —

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

Буду рад объяснениям

Ответ №1:

для поставщика и потребителя контекста обычно я создаю для него 1 крючок, например useBoolean.tsx , возвращаемый BooleanProvider компонент, который вы можете поместить в свой родительский компонент, и useBoolean функцию, которую вы можете импортировать в свой дочерний компонент.

В принципе, любая глобальная функция должна заключать в себя всех своих потомков Provider .

Итак, если вы хотите <CreatePass/> получить доступ к значению от поставщика, оно должно быть дочерним по отношению к его Provider

 <BooleanProvider>
  <CreatePass/>
</BooleanProvider>
 

useBoolean.tsx будет что-то вроде этого

 // 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
import { BooleanProvider } from 'hooks/useBoolean'

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

У Child1 будет Child2, а Child2 будет использовать созданную нами функцию useBoolean

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

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

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

  return <div></div>
}
 

Надеюсь, это поможет вам кое-что прояснить. Я просто пытаюсь объяснить здесь свое понимание использования api контекста react и свой способ его выполнения.

Я попытался создать подобную функцию hooks для упрощения управления кодом — это помогает мне понять, что этот контекст напрямую связан с соглашением об именовании hooks. Функция hook также выдает ошибку, когда она не используется внутри Provider :D. Ваше здоровье!!

Комментарии:

1. Я думаю const BooleanContext = createContext({}) , что он должен быть инициализирован как null вместо object.

2. Да, верно. спасибо за этого человека … если он не определен / равен нулю.. тогда ошибка броска будет работать в крючках..

Ответ №2:

Переместите «const booleanContext = createContext(setIfSignUp);» За пределы компонента, вы не хотите менять ссылку на контекст при каждом рендеринге. Также экспортируйте его для других компонентов.

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

export default App;
 

Затем в CreatePass вы должны импортировать контекст (используется именованный экспорт, поэтому импорт будет выглядеть следующим образом:

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

Теперь это должно сработать.

Редактировать:

Работает, как и ожидалось https://codesandbox.io/s/createcontexttest-0qvvm?file=/src/App.js

ПРАВКА 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>
 

Комментарии:

1. Я уже пробовал это, в CreatePass нем есть undefined . Логический контекст / имя, которое я ему дал, — changeBooleanValue есть undefined . не очень хорошее решение.

2. Я попробовал это в песочнице (ссылка в правке), и это работает, как ожидалось, может быть, попробуйте «отладчик;», если все значения переданы нормально.

3. Ваша ссылка на CodeSandbox-пустой проект, пожалуйста, проверьте.

4. codesandbox.io/s/createcontexttest-0qvvm?file=/src/App.js Попытался переименовать его, попробуй сейчас

5. Это потому CreatePass , что не является внутренним SignUp компонентом. Я изменил его в вашем codesandbox и получил эту ошибку — changeBooleanValue is not a function . App.js — return ( <div className="App"> <h1>Hello CodeSandbox, value: {"" signUpFirst}</h1> <Switch> <Route> <SignUp /> </Route> </Switch> <booleanContext.Provider value={setIfSignUp}> <CreatePass /> </booleanContext.Provider> </div> ); И фиксированный SignUp компонент, который должен быть родителем Createpass

Ответ №3:

Код выглядит нормально. Вы можете исправить ошибку значения по умолчанию при экспорте контекста с пустым объектом {} .

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

и импортируйте его CreatePass.js

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

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

Ответ №4:

во-первых, создайте пользовательский компонент для вашего поставщика контекста:

 import { createContext } from "react";

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

export default CustomContext;
 

затем оберните все ваши компоненты, используя его, например App.js:

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

и тогда вы можете использовать его следующим образом:

 import CustomContext from "./CustomContext";

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

Комментарии:

1. Я пробовал это, но я получаю компонент createPass поверх других компонентов на одной странице, и если я проигнорирую его (и передам весь процесс при регистрации), я получу ошибку — TypeError: changeBooleanValue is not a function .

2. Мне не нужен пользовательский компонент в моем App.js. потому что — const [signUpFirst, setIfSignUp] = useState(true); используется внутри App.js

3. если вы имеете в виду const changeBooleanValue = useContext(booleanContext); раздел, то это абсолютно неправильно! вместо этого вы должны использовать const [_, changeBooleanValue] = useContext(booleanContext); .

4. Я не понимаю этого — changeBooleanValue это имя, которое решили дать ему в CreatePass компоненте. Ваш пример кода не такой, как мой.

5. Я передаю только заданное состояние — setIfSignUp с Поставщиком, вы это видели?