React 和 TypeScript:避免使用上下文默认值
Posted
技术标签:
【中文标题】React 和 TypeScript:避免使用上下文默认值【英文标题】:React & TypeScript: Avoid context default value 【发布时间】:2020-08-03 14:07:47 【问题描述】:为了更好地学习 React、TypeScript 和 Context / Hooks,我正在制作一个简单的 Todo 应用程序。但是,使上下文所需的代码感觉很麻烦。
例如,如果我想更改 Todo 的内容,我必须在三个地方更改它(ITodo 接口、默认上下文值、默认状态值)。如果我想传递新的东西,我必须在三个地方(TodoContext、TodoContext 的默认值和 value=)。有没有更好的办法不用写那么多代码?
import React from 'react'
export interface ITodo
title: string,
body?: string,
id: number,
completed: boolean
interface TodoContext
todos: ITodo[],
setTodos: React.Dispatch<React.SetStateAction<ITodo[]>>
export const TodoContext = React.createContext<TodoContext>(
todos: [title: 'loading', body: 'loading', id: 0, completed: false],
setTodos: () =>
)
export const TodoContextProvider: React.FC<> = (props) =>
const [todos, setTodos] = React.useState<ITodo[]>([title: 'loading', body: 'loading', id: 0, completed: false])
return (
<TodoContext.Provider value=todos, setTodos>
props.children
</TodoContext.Provider>
)
【问题讨论】:
理想情况下这看起来不错,但您可以使用 redux 并将其存储在 redux-store 中,并使用 react-redux connect react-redux.js.org/api/connect 使其可在任何级别访问 【参考方案1】:我的情况可能与您的情况有些不同(我意识到已经有一个公认的答案),但这似乎对我现在有用。 从上面 Aron 的回答中修改,因为在我的情况下使用该技术实际上不起作用。
我的实际上下文的名称当然不同。
export const TodoContext = createContext<any>( as any)
【讨论】:
我的回答对你不起作用怎么办?【参考方案2】:一段时间后,我想我找到了解决此问题的最佳方法。
import React from 'react'
export interface ITodo
title: string,
body?: string,
id: number,
completed: boolean
const useValue = () =>
const [todos, setTodos] = React.useState<ITodo[]>([])
return
todos,
setTodos
export const TodoContext = React.createContext( as ReturnType<typeof useValue>)
export const TodoContextProvider: React.FC<> = (props) =>
return (
<TodoContext.Provider value=useValue()>
props.children
</TodoContext.Provider>
)
这样,在您的上下文中添加新内容时会出现单点更改,而不是最初的三点更改。享受吧!
【讨论】:
【参考方案3】:来自react documentation的备注:
只有当组件在树中没有匹配的 Provider 时才使用 defaultValue 参数。
我更喜欢这样做的方式是实际指定默认值可以是undefined
const TodoContext = React.createContext<ITodoContext | undefined>(undefined)
然后,为了使用上下文,我创建了一个钩子来为我做检查:
function useTodoContext()
const context = useContext(TodoContext)
if (context === undefined)
throw new Error("useTodoContext must be within TodoProvider")
return context
为什么我喜欢这种方法?
它会立即给我反馈为什么我的上下文值是undefined
。
如需进一步参考,请查看Kent C. Dodds 的这篇博文
【讨论】:
【参考方案4】:没有办法避免声明接口和运行时值,因为 TS 的类型在运行时会消失,所以您只剩下运行时值。你不能从另一个生成一个。
但是,如果您知道您只会访问 TodoContextProvider
组件中的上下文,您可以通过欺骗一点点来避免初始化 TodoContext
,并告诉 TS 您传递的内容很好。
const TodoContext = React.createContext<TodoContext>( as TodoContext)
如果您始终确保只访问TodoContextProvider
内部的上下文,其中todos
和setTodos
是用useState
创建的,那么您可以安全地跳过createContext
内部的初始化TodoContext
,因为该初始value 永远不会被实际访问。
【讨论】:
那太好了。是的,通常情况就是这样。谢谢以上是关于React 和 TypeScript:避免使用上下文默认值的主要内容,如果未能解决你的问题,请参考以下文章
React useContext & Typescript:不是数组类型
如何使用enum作为react / typescript中的道具
套接字 IO 客户端 + React Typescript + 上下文 API 导致 TypeError:无法分配给对象“#<Object>”的只读属性“exports”