将 createContext 和 useReducer 与打字稿一起使用时,无法传递对象状态并分派给提供者
Unable to pass objects state and dispatch to provider when using createContext and useReducer with typescript
我正在尝试使用 contextApi
和 hooks 实现类似于 redux 的行为,但我在使用 typescript 时遇到了一些问题。
我想提供我的应用程序的状态和调度,以便能够从组件内访问和修改商店。问题是,当我使用 createContext 时,手头仍然没有 state
和 dispatch
对象,因为我只能在 React
中调用 useReducer
零件。因此我只能调用 createContext
声明参数的类型是 any
,以便在那时传递 null 并稍后传递另一个调度和状态。
import React, { createContext, useReducer } from 'react';
import reducerAuth, { initialState } from './reducerAuth';
const ContextAuth = createContext<any>(null);
const StateProvider = (
{ children }:{children:JSX.Element},
) => {
const { Provider } = ContextAuth;
const [state, dispatch] = useReducer(reducerAuth, initialState);
return (<Provider value={{ state, dispatch }}>{children}</Provider>);
};
export { ContextAuth, StateProvider };
有没有一种方法可以让我传递 state
和 dispatch
而不必声明类型 any
并且没有打字稿冲突?
我不想使用redux
来实现所有这些,因为我想使用原生工具,但 redux 似乎更容易,尽管非常相似。
我想传递对象的类型{state,dispatch}
来创建上下文,方法如下:
const [state, dispatch] = useReducer(reducerAuth, initialState);
type UseReducer = {
state: typeof state,
dispatch: typeof dispatch,
}
const ContextAuth = createContext<UseReducer | null>(null);
但在这种情况下,我无法再导出 Context Auth,因为它是在 StateProvider
函数内部创建的。
问题的根源在于您试图在创建对象后推断对象的类型,而不是了解将创建什么类型的对象。在我看来,这是一个倒退的设计。
尽可能避免使用 typeof
。有些事情您可以使用 type
或 interface
来明确,而 typeof
无法自行推断。 string
"myString" 可以是任何 string
值,还是字符串文字? null
属性 只能是 null
还是 null
或其他类型?那会是什么其他类型?希望你明白了。
dispatch
具有已知类型。它是一个采取行动和 returns void
的函数。您不需要使用 typeof dispatch
来获取它的类型。
type Dispatch<A> = (value: A) => void;
通用变量 A
表示可接受的 action
参数。您使用什么取决于您希望应用程序的类型严格程度。您可以将其设置为特定操作类型的联合,或者设置为您的所有操作都将实现的通用接口。 Redux 导出通用类型 Action
and AnyAction
但 React 没有,所以你必须自己定义它。
interface MyAction {
type: string;
payload: any;
}
type MyDispatch = Dispatch<MyAction>
同样,您应该已经知道 State
的预期 type/interface。如果没有,请定义它!
这是一个完整的代码示例。实现类型的地方在你的 initialState
和 reducerAuth
上。如果输入正确,则 StateProvider
不需要任何额外输入,因为 useReducer
挂钩可以推断出 state
和 dispatch
.
的类型
import React, { createContext, useReducer } from 'react';
interface MyState {
// some actual data here
}
// initialState must fulfill the `MyState` interface
const initialState: MyState = {};
// just an example, you can define this type however you want
interface MyAction {
type: string;
payload: any;
}
// reducer declaration depends on the types for `MyState` and `MyAction`
const reducerAuth = (state: MyState, action: MyAction): MyState => {
// actual reducer here
return state;
};
// these are the values in your context object
interface MyContext {
state: MyState;
dispatch: React.Dispatch<MyAction>
}
const ContextAuth = createContext<MyContext | null>(null);
const StateProvider = ({ children }: { children: JSX.Element }) => {
const { Provider } = ContextAuth;
const [state, dispatch] = useReducer(reducerAuth, initialState);
return (
<Provider value={{ state, dispatch }}>
{children}
</Provider>
);
};
我正在尝试使用 contextApi
和 hooks 实现类似于 redux 的行为,但我在使用 typescript 时遇到了一些问题。
我想提供我的应用程序的状态和调度,以便能够从组件内访问和修改商店。问题是,当我使用 createContext 时,手头仍然没有 state
和 dispatch
对象,因为我只能在 React
中调用 useReducer
零件。因此我只能调用 createContext
声明参数的类型是 any
,以便在那时传递 null 并稍后传递另一个调度和状态。
import React, { createContext, useReducer } from 'react';
import reducerAuth, { initialState } from './reducerAuth';
const ContextAuth = createContext<any>(null);
const StateProvider = (
{ children }:{children:JSX.Element},
) => {
const { Provider } = ContextAuth;
const [state, dispatch] = useReducer(reducerAuth, initialState);
return (<Provider value={{ state, dispatch }}>{children}</Provider>);
};
export { ContextAuth, StateProvider };
有没有一种方法可以让我传递 state
和 dispatch
而不必声明类型 any
并且没有打字稿冲突?
我不想使用redux
来实现所有这些,因为我想使用原生工具,但 redux 似乎更容易,尽管非常相似。
我想传递对象的类型{state,dispatch}
来创建上下文,方法如下:
const [state, dispatch] = useReducer(reducerAuth, initialState);
type UseReducer = {
state: typeof state,
dispatch: typeof dispatch,
}
const ContextAuth = createContext<UseReducer | null>(null);
但在这种情况下,我无法再导出 Context Auth,因为它是在 StateProvider
函数内部创建的。
问题的根源在于您试图在创建对象后推断对象的类型,而不是了解将创建什么类型的对象。在我看来,这是一个倒退的设计。
尽可能避免使用 typeof
。有些事情您可以使用 type
或 interface
来明确,而 typeof
无法自行推断。 string
"myString" 可以是任何 string
值,还是字符串文字? null
属性 只能是 null
还是 null
或其他类型?那会是什么其他类型?希望你明白了。
dispatch
具有已知类型。它是一个采取行动和 returns void
的函数。您不需要使用 typeof dispatch
来获取它的类型。
type Dispatch<A> = (value: A) => void;
通用变量 A
表示可接受的 action
参数。您使用什么取决于您希望应用程序的类型严格程度。您可以将其设置为特定操作类型的联合,或者设置为您的所有操作都将实现的通用接口。 Redux 导出通用类型 Action
and AnyAction
但 React 没有,所以你必须自己定义它。
interface MyAction {
type: string;
payload: any;
}
type MyDispatch = Dispatch<MyAction>
同样,您应该已经知道 State
的预期 type/interface。如果没有,请定义它!
这是一个完整的代码示例。实现类型的地方在你的 initialState
和 reducerAuth
上。如果输入正确,则 StateProvider
不需要任何额外输入,因为 useReducer
挂钩可以推断出 state
和 dispatch
.
import React, { createContext, useReducer } from 'react';
interface MyState {
// some actual data here
}
// initialState must fulfill the `MyState` interface
const initialState: MyState = {};
// just an example, you can define this type however you want
interface MyAction {
type: string;
payload: any;
}
// reducer declaration depends on the types for `MyState` and `MyAction`
const reducerAuth = (state: MyState, action: MyAction): MyState => {
// actual reducer here
return state;
};
// these are the values in your context object
interface MyContext {
state: MyState;
dispatch: React.Dispatch<MyAction>
}
const ContextAuth = createContext<MyContext | null>(null);
const StateProvider = ({ children }: { children: JSX.Element }) => {
const { Provider } = ContextAuth;
const [state, dispatch] = useReducer(reducerAuth, initialState);
return (
<Provider value={{ state, dispatch }}>
{children}
</Provider>
);
};