#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.js3. если вы имеете в виду
const changeBooleanValue = useContext(booleanContext);
раздел, то это абсолютно неправильно! вместо этого вы должны использоватьconst [_, changeBooleanValue] = useContext(booleanContext);
.4. Я не понимаю этого —
changeBooleanValue
это имя, которое решили дать ему вCreatePass
компоненте. Ваш пример кода не такой, как мой.5. Я передаю только заданное состояние —
setIfSignUp
с Поставщиком, вы это видели?