React 状态管理:上下文 API 作为全局存储
Posted
技术标签:
【中文标题】React 状态管理:上下文 API 作为全局存储【英文标题】:React State Management: Context API as global store 【发布时间】:2021-03-08 19:03:48 【问题描述】:我正在使用 TypeScript 开发一个 React Web 应用程序。 我想使用 React Hooks 和 Context API 设置状态管理,发现这个很酷、简单且简短的 tutorial。
我按照教程进行操作,但我的编译器显示了几个错误。我认为这是基本的类型错误,我不明白(我更习惯 javascript 而不是 TypeScript)。
我的状态上下文:
import React, createContext, useContext, useReducer from 'react';
export interface IState
isAuth: boolean;
user: string;
interface IContextProps
state: IState;
dispatch: ( type : type: string ) => void;
export const StateContext = createContext( as IContextProps);
export const StateProvider = ( reducer, initialState, children ) => (
<StateContext.Provider value=useReducer(reducer, initialState)>
children
</StateContext.Provider>
);
export const useStateValue = () => useContext(StateContext);
我的状态减速器:
import initialState from './InitialState';
export const reducer = (state = initialState, action: any) =>
switch (action.type)
case 'setObj':
return
...state,
obj: action.objValue,
;
default:
return state;
;
我的初始状态:
import emptyObj from '../interfaces/IObj';
export const initialState =
obj: emptyObj,
;
我的应用:
import React from 'react';
import StateProvider from './utils/StateContext';
import initialState from './globals/constants/InitialState';
import reducer from './globals/constants/StateReducer';
function App()
return (
<div className='App'>
<header className='App-header'>
<StateProvider initialState=initialState reducer=reducer>
<p>Hello World</p>
</StateProvider>
</header>
</div>
);
export default App;
错误仅在状态上下文文件中:
1.) 状态上下文
第一个错误是状态上下文。在教程中它被定义为:
export const StateContext = createContext();
并且编译器会抛出一个错误。
如果我使用export const StateContext = createContext(undefined);
,那么错误就消失了。
此外,如果我使用(如开头所述)export const StateContext = createContext( as IContextProps);
并添加接口 IState 和 IContextProps 那么它也可以工作。我想那部分现在很好。
2.) 状态提供者export const StateProvider = ( reducer, initialState, children ) => ...
编译器为 reducer、initialState 和 children 抛出相同的错误:Binding Element [reducer / initialState / children] 隐含任何类型。
3.) 值value=useReducer(reducer, initialState)>...
编译器喊:
类型“[未知,DispatchWithoutAction]”不可分配给类型“IContextProps”.ts(2322)
index.d.ts(335, 9):预期类型来自属性“值”,该属性在此处声明为类型“IntrinsicAttributes & ProviderProps”
提前感谢您的帮助。如果您需要更多信息,请告诉我。
【问题讨论】:
1)createContext
函数需要一个默认值,以防有人试图在提供程序之外使用它。正如您所指出的,这可能只是未定义或空对象,但这是一项要求。 2)这是 Typescript 的一部分(可以关闭),但它告诉你它不能推断 reducer、inititalState 和 children 的类型。您将不得不更改您的代码,以便它可以推断它们或手动输入它们。 3) useReducer
无法推断您的状态的类型(由未知数显示),解决此问题的方法可能是将您的初始状态键入 IState。
【参考方案1】:
问题可能是因为
<StateContext.Provider value=useReducer(reducer, initialState)>
useReducer 返回一个数组,Provider 需要一个对象。
const [state, dispatch] = useReducer(reducers, initialState);
return (
<StateContext.Provider value= state, dispatch >
children
</StateContext.Provider>
);
我已经写了一篇关于你可以的文章
文章:State Management with React Hooks and Context API
运行示例:https://stackblitz.com/edit/reactjs-usecontext-usereducer-state-management
【讨论】:
【参考方案2】:我最近遇到了同样的问题,我通过这种方式解决了它,我希望它对你也有帮助。我更新了您的代码,如下面的 sn-ps 所示,
export interface IState
user: any,
theme: boolean,
drawer: boolean,
export const initialState =
user: null,
theme: false,
drawer: false,
export enum actionTypes
SET_THEME = "SET_THEME",
SET_USER = "SET_USER",
OPEN_DRAWER = "OPEN_DRAWER",
export type IAction =
|
type: actionTypes.SET_USER,
value: any
|
type: actionTypes.SET_THEME,
value: boolean
|
type: actionTypes.OPEN_DRAWER,
value: boolean
const reducer = (state: IState, action:IAction): IState =>
switch (action.type)
case actionTypes.SET_THEME:
return
...state,
theme: action.value,
case actionTypes.SET_USER:
return
...state,
user: action.value,
case actionTypes.OPEN_DRAWER:
return
...state,
user: action.value,
default:
return state
export default reducer;
上下文提供者(StateProvider)应该更新为...
import React, useReducer, createContext, useContext, ReactElement from 'react';
import initialState, IState from "./Reducer";
const StateContext = createContext<IState | any>(initialState);
interface StateProps
children: ReactElement,
initialState: (IState | any),
reducer: (IState | any),
export const StateProvider = (children,initialState, reducer : StateProps): ReactElement =>
// const [state, dispatch] = useReducer(initialState, reducer);
return(
<StateContext.Provider value=useReducer(initialState, reducer)>
children
</StateContext.Provider>
);
export const useStateValue = () => useContext(StateContext);
然后用上下文提供者 (StateProvider) 包装你的主应用
import HeadTag, Layout from "../components/components";
import reducer, initialState from "../provider/Reducer";
import StateProvider from "../provider/StateProvider";
function MyApp( Component, pageProps : AppProps)
return (
<>
<HeadTag />
<StateProvider initialState=initialState reducer=reducer >
<Layout>
<Component ...pageProps />
</Layout>
</StateProvider>
</>
);
export default MyApp;
在您的应用中使用它
/* data layer */
const [user, theme, drawer, dispatch] = useReducer(reducer, initialState);
/* switch between dark and light mode */
const handleTheme = () =>
if(theme)
dispatch(
type: actionTypes.SET_THEME,
value: false,
);
else
dispatch(
type: actionTypes.SET_THEME,
value: true,
);
我希望这能解决你的问题。
【讨论】:
以上是关于React 状态管理:上下文 API 作为全局存储的主要内容,如果未能解决你的问题,请参考以下文章
React Context API,从子组件设置上下文状态,而不是将函数作为道具传递
使用上下文 API (React.js) 仅更改状态对象中的特定键