所以我在React Context + Typescript上遇到了一个很奇怪的问题。
在上面的示例中,您可以看到我正在尝试做的实际工作。本质上,我正在使用新的useContext方法管理状态,并且它可以完美地工作。
但是,当我尝试在盒子上执行此操作时,似乎找不到通过useReducer传递的状态值。
export function AdminStoreProvider(props: any) {
const [state, dispatch] = useReducer(reducer, initialState);
// state.isAuth is avail here
// state.user is avail here
const value = { state, dispatch };
// value.state.isAuth is avail here
return (
/* value does not contain state once applied to the value prop */
<AdminStore.Provider value={value}>{props.children}
</AdminStore.Provider>
);
}
错误消息:
Type '{ state: { isAuth: boolean; user: string; }; dispatch:
Dispatch<Actions>; }' is missing the following properties from type
'IState': isAuth, user
请记住,我正在使用的代码正是我在盒子上使用的代码,我什至从沙箱中下载了代码并尝试运行它,但是它不起作用。
我正在使用VSCode 1.31
我设法推断出,如果我从以下位置更改创建上下文的方式:
export const AdminStore = React.createContext(initialState);
到
export const AdminStore = React.createContext(null);
value属性不再引发该错误。
但是,现在useContext返回一个错误:状态不存在为null。同样,如果我将上下文的defaultState设置为{}。
当然,如果我
React.createContext();
然后TS大喊大叫没有提供defaultValue。
在沙箱中,创建上下文对象的所有3个版本都可以正常工作。
预先感谢您的任何建议。
答案 0 :(得分:4)
看来React.createContext
的defaultValue
值应为以下类型:
interface IContextProps {
state: IState;
dispatch: ({type}:{type:string}) => void;
}
为此类型创建Context
对象后,例如:
export const AdminStore = React.createContext({} as IContextProps);
Provider React组件不应再抱怨该错误。
以下是更改列表:
admin-store.tsx
import React, { useReducer } from "react";
import { initialState, IState, reducer } from "./reducer";
interface IContextProps {
state: IState;
dispatch: ({type}:{type:string}) => void;
}
export const AdminStore = React.createContext({} as IContextProps);
export function AdminStoreProvider(props: any) {
const [state, dispatch] = useReducer(reducer, initialState);
const value = { state, dispatch };
return (
<AdminStore.Provider value={value}>{props.children}</AdminStore.Provider>
);
}
答案 1 :(得分:0)
我玩得很开心,所以我想分享自己的想法。
SidebarProps
表示上下文的状态。除了reducer动作外,其他所有东西都可以按原样使用。
import React, { createContext, Dispatch, Reducer, useContext, useReducer } from 'react';
interface Actions {
type: string;
value: any;
}
interface SidebarProps {
show: boolean;
content: JSX.Element | null;
}
interface SidebarProviderProps {
reducer: Reducer<SidebarProps, Actions>;
initState: SidebarProps;
}
interface InitContextProps {
state: SidebarProps;
dispatch: Dispatch<Actions>;
}
export const SidebarContext = createContext({} as InitContextProps);
export const SidebarProvider: React.FC<SidebarProviderProps> = ({ reducer, initState, children }) => {
const [state, dispatch] = useReducer(reducer, initState);
const value = { state, dispatch };
return (
<SidebarContext.Provider value={value}>
{children}
</SidebarContext.Provider>
);
};
export const useSidebar = () => useContext(SidebarContext);
const SidebarController: React.FC = ({ children }) => {
const initState: SidebarProps = {
show: false,
content: null
};
const reducer: Reducer<SidebarProps, Actions> = (state, action) => {
switch (action.type) {
case 'setShow':
return {
...state,
show: action.value
};
case 'setContent':
return {
...state,
content: action.value
};
default:
return state;
}
};
return (
<SidebarProvider reducer={reducer} initState={initState}>
{children}
</SidebarProvider>
);
};
export default SidebarController;