将 createContext 和 useReducer 与打字稿一起使用时,无法传递对象状态并分派给提供者

Unable to pass objects state and dispatch to provider when using createContext and useReducer with typescript

我正在尝试使用 contextApi 和 hooks 实现类似于 redux 的行为,但我在使用 typescript 时遇到了一些问题。

我想提供我的应用程序的状态和调度,以便能够从组件内访问和修改商店。问题是,当我使用 createContext 时,手头仍然没有 statedispatch 对象,因为我只能在 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 };

有没有一种方法可以让我传递 statedispatch 而不必声明类型 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。有些事情您可以使用 typeinterface 来明确,而 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。如果没有,请定义它!

这是一个完整的代码示例。实现类型的地方在你的 initialStatereducerAuth 上。如果输入正确,则 StateProvider 不需要任何额外输入,因为 useReducer 挂钩可以推断出 statedispatch.

的类型
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>
    );
};