typescript 在打字稿中反应 createContext 问题?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/54577865/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
React createContext issue in Typescript?
提问by bauervision
So I'm having a very weird issue with React Context + Typescript.
所以我在 React Context + Typescript 上遇到了一个非常奇怪的问题。
In the above example, you can see what I'm trying to do actually work. Essentially I'm managing state with the new useContext method, and it works perfectly.
在上面的例子中,你可以看到我正在尝试做的实际工作。本质上,我正在使用新的 useContext 方法管理状态,并且它运行良好。
However, when I try to do this on my box, it cannot seem to find the state values being passed through the useReducer.
但是,当我尝试在我的盒子上执行此操作时,它似乎无法找到通过 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>
);
}
Error message:
错误信息:
Type '{ state: { isAuth: boolean; user: string; }; dispatch:
Dispatch<Actions>; }' is missing the following properties from type
'IState': isAuth, user
Keep in mind the code I'm using is exactly what I'm using on my box, I've even downloaded the code from sandbox and tried running it, and it doesn't work.
请记住我正在使用的代码正是我在我的盒子上使用的代码,我什至从沙箱下载了代码并尝试运行它,但它不起作用。
I'm using VSCode 1.31
我正在使用 VSCode 1.31
I've managed to deduce that if I change how I create my context from:
我已经设法推断出,如果我改变我创建上下文的方式:
export const AdminStore = React.createContext(initialState);
to
到
export const AdminStore = React.createContext(null);
The value property no longer throws that error.
value 属性不再抛出该错误。
However, now useContext returns an error: state doesn't exist on null. And same if I set defaultState for context to {}.
但是,现在 useContext 返回一个错误:状态在 null 上不存在。同样,如果我将上下文的 defaultState 设置为 {}。
And of course if I
当然如果我
React.createContext();
Then TS yells about no defaultValue being provided.
然后 TS 大喊没有提供 defaultValue。
In sandbox, all 3 versions of creating the context object work fine.
在沙箱中,创建上下文对象的所有 3 个版本都可以正常工作。
Thanks in advance for any advice.
提前感谢您的任何建议。
回答by Vadim Gremyachev
It appears defaultValue
value for React.createContext
is expected to be of type:
它的defaultValue
值 似乎React.createContext
是以下类型:
interface IContextProps {
state: IState;
dispatch: ({type}:{type:string}) => void;
}
Once Context
object is created for this type, for example like this:
一旦Context
为此类型创建了对象,例如像这样:
export const AdminStore = React.createContext({} as IContextProps);
Provider React component should no longer complain about the error.
Provider React 组件不应再抱怨错误。
Here is the list of changes:
以下是更改列表:
admin-store.tsx
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>
);
}
回答by Jerad
I had a fun time with this so I figured I'd share what I came up with.
我玩得很开心,所以我想我会分享我的想法。
The SidebarProps
represent the context's state. Everything else, besides the reducer actions, can essentially be used as is.
该SidebarProps
表示上下文的状态。除了减速器操作之外,其他所有内容基本上都可以按原样使用。
Here is a nice article explaining the exact same workaround (Not in TypeScript) : Mixing Hooks and Context Api
这是一篇很好的文章,解释了完全相同的解决方法(不在 TypeScript 中):Mixing Hooks and Context Api
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;