React TS useContext useReducer 钩子
Posted
技术标签:
【中文标题】React TS useContext useReducer 钩子【英文标题】:React TS useContext useReducer hook 【发布时间】: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 钩子的正确方法吗?
【问题讨论】:
【参考方案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
钩子,它返回state
、dispatch
和其他有用的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 让孩子们也可以使用它。 我的错,没看到你的最后一句话。立即查看更新。以上是关于React TS useContext useReducer 钩子的主要内容,如果未能解决你的问题,请参考以下文章