【问题标题】:How do I set Typescript types for useReducer useContext for the following contextapi code?如何为以下 contextapi 代码的 useReducer useContext 设置 Typescript 类型?
【发布时间】:2020-10-26 02:48:03
【问题描述】:

我想在下面的代码中使用正确的 TS 类型,而不是任何类型。我是反应 TS 的新手,请帮助...

如何为以下上下文 API 代码的 useReducer useContext 设置 typescript 类型:

import React, {createContext, Dispatch} from 'react';
import {firebaseUser} from '../@types/User';

interface Actions {
  SET_IMAGENAME: string;
  SET_USER: string;
}

export const Actions: Actions = {
  SET_IMAGENAME: 'SET_IMAGENAME',
  SET_USER: 'SET_USER',
};

function action(type: string) {
  return {type};
}

function actionPayload(type: string, payload: any) { //here
  return {type, payload};
}

export const Dispatches = {
  setImageName: action,
  setUser: actionPayload,
};

interface State {
  imgName: string;
  user: firebaseUser;
}

const initialState = {
  imgName: '',
  user: {} as firebaseUser,
};

function reducer(state = initialState, action: {type: string; payload: any}) { //here
  switch (action.type) {
    case Actions.SET_IMAGENAME:
      return {...state, imgName: 'sample image'};
    case Actions.SET_USER:
      return {...state, user: action.payload};
    default:
      return state;
  }
}

export const Store = createContext<{
  state: State;
  dispatch: Dispatch<any>; //here
}>({
  state: initialState,
  dispatch: () => null,
});

export function StoreProvider({children}: JSX.ElementChildrenAttribute): JSX.Element {
  const [state, dispatch] = React.useReducer(reducer, initialState);
  return <Store.Provider value={{state, dispatch}}>{children}</Store.Provider>;
}

任何人都可以帮助我吗?不胜感激?

谢谢

【问题讨论】:

    标签: reactjs typescript context-api react-typescript use-reducer


    【解决方案1】:

    我希望这个解决方案能给你一个好主意。

    https://gist.github.com/sw-yx/f18fe6dd4c43fddb3a4971e80114a052

    https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/context/#extended-example

    export function createCtx<StateType, ActionType>(
      reducer: React.Reducer<StateType, ActionType>,
      initialState: StateType,
    ) {
      const defaultDispatch: React.Dispatch<ActionType> = () => initialState // we never actually use this
      const ctx = React.createContext({
        state: initialState,
        dispatch: defaultDispatch, // just to mock out the dispatch type and make it not optioanl
      })
      function Provider(props: React.PropsWithChildren<{}>) {
        const [state, dispatch] = React.useReducer<React.Reducer<StateType, ActionType>>(reducer, initialState)
        return <ctx.Provider value={{ state, dispatch }} {...props} />
      }
      return [ctx, Provider] as const
    }
    // usage
    const initialState = { count: 0 }
    type AppState = typeof initialState
    type Action =
      | { type: 'increment' }
      | { type: 'add'; payload: number }
      | { type: 'minus'; payload: number }
      | { type: 'decrement' }
    
    function reducer(state: AppState, action: Action): AppState {
      switch (action.type) {
        case 'increment':
          return { count: state.count + 1 }
        case 'decrement':
          return { count: state.count - 1 }
        case 'add':
          return { count: state.count + action.payload }
        case 'minus':
          return { count: state.count - action.payload }
        default:
          throw new Error()
      }
    }
    const [ctx, CountProvider] = createCtx(reducer, initialState)
    export const CountContext = ctx
    
    // top level example usage
    export function App() {
      return (
        <CountProvider>
          <Counter />
        </CountProvider>
      )
    }
    
    // example usage inside a component
    function Counter() {
      const { state, dispatch } = React.useContext(CountContext)
      return (
        <div>
          Count: {state.count}
          <button onClick={() => dispatch({ type: 'increment' })}>+</button>
          <button onClick={() => dispatch({ type: 'add', payload: 5 })}>+5</button>
          <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
          <button onClick={() => dispatch({ type: 'minus', payload: 5 })}>+5</button>
        </div>
      )
    }

    【讨论】:

      【解决方案2】:

      这真的取决于有效负载可以包含什么,它可以包含图像或 FirebaseUser 实例的字符串,您可以设置payload: string | FirebaseUser

      import React, {createContext, Dispatch} from 'react';
      import {firebaseUser} from '../@types/User';
      
      interface Actions {
        SET_IMAGENAME: string;
        SET_USER: string;
      }
      
      export const Actions: Actions = {
        SET_IMAGENAME: 'SET_IMAGENAME',
        SET_USER: 'SET_USER',
      };
      
      function action(type: string) {
        return {type};
      }
      
      // If payload can contain string of image or FirebaseUser instance
      // it will be string | FirebaseUser
      // if payload will only contain FirebaseUser instance you just need payload: FirebaseUser
      export type ActionType = {
       type: string,
       payload: string | FirebaseUser
      }
      
      // If payload can contain string of image or FirebaseUser instance
      // it will be string | FirebaseUser
      // if payload will only contain FirebaseUser instance you just need payload: FirebaseUser
      function actionPayload(type: string, payload: string | FirebaseUser ) { //here
        return {type, payload};
      }
      
      export const Dispatches = {
        setImageName: action,
        setUser: actionPayload,
      };
      
      interface State {
        imgName: string;
        user: FirebaseUser;
      }
      
      const initialState = {
        imgName: '',
        user: {} as firebaseUser,
      };
      
      // set Action type here
      function reducer(state = initialState, action: ActionType) {
        switch (action.type) {
          case Actions.SET_IMAGENAME:
            // need to cast type herer
            return {...state, imgName: action.payload as string};
          case Actions.SET_USER:
            // need to cast type herer
            return {...state, user: action.payload as firebaseUser};
          default:
            return state;
        }
      }
      
      export const Store = createContext<{
        state: State;
        dispatch: Dispatch<ActionType>; //action type here
      }>({
        state: initialState,
        dispatch: () => null,
      });
      
      export function StoreProvider({children}: JSX.ElementChildrenAttribute): JSX.Element {
        const [state, dispatch] = React.useReducer(reducer, initialState);
        return <Store.Provider value={{state, dispatch}}>{children}</Store.Provider>;
      }
      

      【讨论】:

      【解决方案3】:

      这也是我的解决方案,通过添加类型文件来更清洁您的文件结构,我希望您觉得它有用: myCodesandboxRepo

      【讨论】:

        猜你喜欢
        • 2023-01-23
        • 1970-01-01
        • 2017-07-28
        • 2019-12-09
        • 2021-09-11
        • 1970-01-01
        • 2021-10-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多