【问题标题】:React TS useContext useReducer hookReact TS useContext useReducer 钩子
【发布时间】:2019-12-09 09:49:28
【问题描述】:

我无法弄清楚这段代码中的类型错误是什么

import React from 'react';

interface IMenu {
  items: {
    title: string,
    active: boolean,
    label: string
  }[]
}


type Action =
  | { type: 'SET_ACTIVE', label: string }

const initialState: IMenu = {
  items: [
    { title: 'Home', active: false, label: 'home' },
    { title: 'Customer', active: false, label: 'customer' },
    { title: 'Employee', active: false, label: 'employee' },
    { title: 'Report', active: false, label: 'report' },
  ]
}

const reducer = (state: IMenu = initialState, action: Action) => {
  switch (action.type) {
    case 'SET_ACTIVE': {
      const label = action.label;
      const items = state.items.map((item) => {
        if (item.label === label) {
          return { ...item, active: true };
        }
        return { ...item, active: false }
      })
      return { items }
    }
    default:
      throw new Error();
  }
};

export const MenuContext = React.createContext(initialState);
export const MenuConsumer = MenuContext.Consumer;

export function MenuProvider(props: any) {
  const [state, dispatch] = React.useReducer(reducer, initialState)
  const value = { state, dispatch };
  console.log(value)
  return (
    <MenuContext.Provider value={value}>
      {props.children}
    </MenuContext.Provider>
  )
}

我收到的错误是这样的

    /Volumes/Tarang External/react-context-typescript/src/context/index.tsx
TypeScript error in /Volumes/Tarang External/react-context-typescript/src/context/index.tsx(49,27):
Property 'items' is missing in type '{ state: { items: { active: boolean; title: string; label: string; }[]; }; dispatch: Dispatch<{ type: "SET_ACTIVE"; label: string; }>; }' but required in type 'IMenu'.  TS2741

    47 |   console.log(value)
    48 |   return (
  > 49 |     <MenuContext.Provider value={value}>
       |                           ^
    50 |       {props.children}
    51 |     </MenuContext.Prov

有人可以帮助指出我到底做错了什么吗?我是打字稿的新手,所以如有必要请指导我。我正在尝试传递状态的上下文值并分派给子组件。我不确定发生了什么。这也是实现 useContext 和 useReducer 钩子的正确方法吗?

【问题讨论】:

    标签: reactjs typescript types react-hooks


    【解决方案1】:

    您的问题是您的上下文应该与initialState 具有相同的类型,但是您将上下文的默认值设置为{ state, dispatch }

    这是不正确的。

    要解决此问题,请将上下文的默认类型设置为{ state, dispatch }(我认为这是您想要的,将上下文的默认类型设置为typeof initialState

    这里是the solution

    【讨论】:

      【解决方案2】:

      我正在尝试将 state 的上下文值传递给子组件。

      MenuContext 类型由 initialState 确定 - 在您的情况下它们不匹配。您可以声明一个自定义上下文值类型:

      type StoreApi = {
        state: typeof initialState
        dispatch: React.Dispatch<Action>
      }
      

      然后像这样定义MenuContext

      // undefined is just the default in case, you don't have a provider defined
      export const MenuContext = React.createContext<StoreApi | undefined>(undefined)
      // or if you want it more like your first example (I would prefer first variant)
      export const MenuContext = React.createContext<StoreApi | typeof initialState>(initialState)
      

      这也是实现 useContext 和 useReducer 钩子的正确方法吗?

      以上是初始化 React 上下文的常见模式。进一步的扩展点:

      1.) 目前,您的所有上下文consumers re-render each render phase,因为value 每次都是一个新的对象引用。如果你的性能很慢(没有过早优化),请记住value

      const value = React.useMemo(() => ({ state, dispatch }), [state])
      

      2.) 创建一个自定义的useMenu 钩子,它返回statedispatch 和其他有用的API 方法。

      function useMenu() {
        const context = React.useContext(MenuContext);
        if (context === undefined) throw new Error(`No provider for MenuContext given`);
        const { state, dispatch } = context;
        const myApiMethod = () => dispatch({ type: "SET_ACTIVE", label: "foo" })
        return { ...context, myApiMethod };
      }
      
      const Client = () => {
        const { state, dispatch, myApiMethod } = useMenu()
        // ...
      }
      

      这样MenuContext就被封装了,不需要使用React.useContext(MenuContext),客户端得到一个量身定制的API。延伸阅读:How to use React Context effectively及其相关文章。

      【讨论】:

      • 有什么区别?我对此有点困惑。
      • 但是我需要通过 dispatch 让孩子们也可以使用它。
      • 我的错,没看到你的最后一句话。立即查看更新。
      猜你喜欢
      • 2022-01-24
      • 1970-01-01
      • 1970-01-01
      • 2020-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多