React useContext 钩子如何用于控制应用程序和条件渲染?
How can the React useContext hook be used to control application and conditional rendering?
我是第一次尝试使用 React hooks,我想最终替换旧的上下文 API。我如何实现 useContext 挂钩来完成全局状态?
我一直在尝试关注 Medium 上的许多教程、其他 Stack overflow 帖子和一些随机博客帖子。下面是我目前的代码:
APP.JS
import React from 'react';
import { AppProvider, useAppValue } from './AppContext';
import FormLogin from './FormLogin';
import FormRegister from './FormRegister';
const App = () => {
const initialState = {
page: <FormLogin/>
}
const reducer = (state, action) => {
switch (action.type) {
case 'loadLogin':
return {
...state,
page: <FormLogin/>
};
case 'loadRegister':
return {
...state,
page: <FormRegister/>
};
default:
return state;
}
};
let { page } = useAppValue();
let currentPage = page ? page : <FormLogin/>
return (
<AppProvider initialState={initialState} reducer={reducer}>
<div className="App">
{currentPage}
</div>
</AppProvider>
);
}
export default App;
APPCONTEXT.JS
import React, { createContext, useContext, useReducer } from 'react';
export const AppContext = createContext();
export const AppProvider = ({reducer, initialState, children}) => (
<AppContext.Provider value={useReducer(reducer, initialState)}>
{children}
</AppContext.Provider>
);
export const useAppValue = () => useContext(AppContext);
这两个表单组件基本上是虚拟组件,其中包含最少的 JSX。
我不断收到多个 "TypeError: Cannot read property 'page' of undefined" 错误。这是使用新的 useContext 挂钩的不正确方法吗?
理想情况下,我希望每个表单都有一个 link,当您单击它时,您会变成另一个表单。即如果您在登录表单但需要注册,它会更改为注册表单,如果您在注册表单但已经有一个帐户,它会将您跳转到登录表单。
首先,您没有正确使用useContext hook 的Reducer Logic。您必须首先了解,除非您在层次结构中有提供者,否则您将无法使用上下文。由于 AppProvider 是在应用程序内部呈现的,因此您将无法在应用程序中使用上下文。
其次,你不能将组件作为标签存储在reducer中,如果你愿意,你可以存储它的引用
所以你的代码最终看起来像
import React from 'react';
import { AppProvider, useAppValue } from './AppContext';
import FormLogin from './FormLogin';
import FormRegister from './FormRegister';
const initialState = {
page: FormLogin
}
const reducer = (state, action) => {
switch (action.type) {
case 'loadLogin':
return {
...state,
page: FormLogin
};
case 'loadRegister':
return {
...state,
page: FormRegister
};
default:
return state;
}
};
const App = () => {
let [{ page: Page }] = useAppValue();
return (
<div className="App">
<Page />
</div>
);
}
export default (props) => (
<AppProvider initialState={initialState} reducer={reducer}>
<App {...props} />
</AppProvider>
)
编辑:确保在您的页面解构周围添加数组。
useContext的使用错误。您在 useContext 的层次结构中没有任何提供者。
这是我已经实现的使用 reducer 的示例方法。
在 Store.js 中,初始化 React 上下文 -
import {createContext} from 'react';
const Context = createContext();
export default Context;
在Reducers.js中,拥有通用状态管理系统的逻辑,
import React, {useReducer} from 'react';
import Context from './Store';
const initialState = {
count: 0,
someothervalue: 'hello'
}
function reducer(state, action) {
const {count, ...otherValues} = state;
switch(action.type) {
case 'increment':
return {count: count + 1, ...otherValues};
case 'decrement':
return (count > 0) ? {count: count - 1, ...otherValues} : state;
default:
return state;
}
}
const ReducerProvider = (props) => {
const [state, dispatch] = useReducer(reducer, initialState);
return (<Context.Provider value={{state, dispatch}}>
{props.children}
</Context.Provider>)
}
export default ReducerProvider;
在App.js,
<ReducerProvider>
..... Your Code .....
</ReducerProvider>
在Component.js,
import Context from '../Store';
....
....
....
const {state, dispatch} = useContext(Context);
return (... your component logic)
我是第一次尝试使用 React hooks,我想最终替换旧的上下文 API。我如何实现 useContext 挂钩来完成全局状态?
我一直在尝试关注 Medium 上的许多教程、其他 Stack overflow 帖子和一些随机博客帖子。下面是我目前的代码:
APP.JS
import React from 'react';
import { AppProvider, useAppValue } from './AppContext';
import FormLogin from './FormLogin';
import FormRegister from './FormRegister';
const App = () => {
const initialState = {
page: <FormLogin/>
}
const reducer = (state, action) => {
switch (action.type) {
case 'loadLogin':
return {
...state,
page: <FormLogin/>
};
case 'loadRegister':
return {
...state,
page: <FormRegister/>
};
default:
return state;
}
};
let { page } = useAppValue();
let currentPage = page ? page : <FormLogin/>
return (
<AppProvider initialState={initialState} reducer={reducer}>
<div className="App">
{currentPage}
</div>
</AppProvider>
);
}
export default App;
APPCONTEXT.JS
import React, { createContext, useContext, useReducer } from 'react';
export const AppContext = createContext();
export const AppProvider = ({reducer, initialState, children}) => (
<AppContext.Provider value={useReducer(reducer, initialState)}>
{children}
</AppContext.Provider>
);
export const useAppValue = () => useContext(AppContext);
这两个表单组件基本上是虚拟组件,其中包含最少的 JSX。
我不断收到多个 "TypeError: Cannot read property 'page' of undefined" 错误。这是使用新的 useContext 挂钩的不正确方法吗?
理想情况下,我希望每个表单都有一个 link,当您单击它时,您会变成另一个表单。即如果您在登录表单但需要注册,它会更改为注册表单,如果您在注册表单但已经有一个帐户,它会将您跳转到登录表单。
首先,您没有正确使用useContext hook 的Reducer Logic。您必须首先了解,除非您在层次结构中有提供者,否则您将无法使用上下文。由于 AppProvider 是在应用程序内部呈现的,因此您将无法在应用程序中使用上下文。
其次,你不能将组件作为标签存储在reducer中,如果你愿意,你可以存储它的引用
所以你的代码最终看起来像
import React from 'react';
import { AppProvider, useAppValue } from './AppContext';
import FormLogin from './FormLogin';
import FormRegister from './FormRegister';
const initialState = {
page: FormLogin
}
const reducer = (state, action) => {
switch (action.type) {
case 'loadLogin':
return {
...state,
page: FormLogin
};
case 'loadRegister':
return {
...state,
page: FormRegister
};
default:
return state;
}
};
const App = () => {
let [{ page: Page }] = useAppValue();
return (
<div className="App">
<Page />
</div>
);
}
export default (props) => (
<AppProvider initialState={initialState} reducer={reducer}>
<App {...props} />
</AppProvider>
)
编辑:确保在您的页面解构周围添加数组。
useContext的使用错误。您在 useContext 的层次结构中没有任何提供者。
这是我已经实现的使用 reducer 的示例方法。
在 Store.js 中,初始化 React 上下文 -
import {createContext} from 'react';
const Context = createContext();
export default Context;
在Reducers.js中,拥有通用状态管理系统的逻辑,
import React, {useReducer} from 'react';
import Context from './Store';
const initialState = {
count: 0,
someothervalue: 'hello'
}
function reducer(state, action) {
const {count, ...otherValues} = state;
switch(action.type) {
case 'increment':
return {count: count + 1, ...otherValues};
case 'decrement':
return (count > 0) ? {count: count - 1, ...otherValues} : state;
default:
return state;
}
}
const ReducerProvider = (props) => {
const [state, dispatch] = useReducer(reducer, initialState);
return (<Context.Provider value={{state, dispatch}}>
{props.children}
</Context.Provider>)
}
export default ReducerProvider;
在App.js,
<ReducerProvider>
..... Your Code .....
</ReducerProvider>
在Component.js,
import Context from '../Store';
....
....
....
const {state, dispatch} = useContext(Context);
return (... your component logic)