有很多文章介绍了如何用上下文和钩子来替换Redux(例如,请参见this one from Kent Dodds)。基本思想是通过上下文来提供全局状态,而不是将其放在Redux存储中。但这种方法存在一个大问题:无论您的组件是否关心刚刚改变的那部分状态,订阅了上下文的组件都将被重新呈现.对于功能组件,React-redux通过useSelector钩子解决了这个问题.所以我的问题是:是否可以创建一个像useSelector这样的钩子来获取上下文的一部分而不是Redux存储区,它具有与useSelector相同的签名,并且像useSelector一样,只在上下文的“选定”部分发生更改时才重新呈现组件?
(note:this discussion在React Github页面上提示这是不可能的)
8条答案
按热度按时间1szpjjfi1#
不,这是不可能的。任何时候你把一个新的上下文值放入一个提供者,* 所有 * 消费者都会重新呈现,即使他们只需要那个上下文值的一部分。
这是specifically one of the reasons why we gave up on using context to propagate state updates in React-Redux v6, and switched back to using direct store subscriptions in v7。
有a community-written React RFC to add selectors to context,但没有迹象表明React团队会真正实施该RFC。
nnsrf1az2#
正如markerikson所回答的,这是不可能的,但是您可以解决这个问题,而不使用外部依赖项,也不需要退回到手动订阅。
作为一种解决方案,您可以 * 让组件重新呈现,但跳过VDOM协调 *,方法是使用
useMemo
存储返回的React元素。这是因为在内部,当React比较两个版本的虚拟DOM节点时,如果它遇到完全相同的引用,它将完全跳过协调该节点。
vybvopom3#
我创建了一个使用ContextAPI管理状态的工具包,它提供了
useSelector
(带有自动完成功能)和useDispatch
。该库可从以下位置获得:
它使用:
createSlice
from @reduxjs/toolkit以使状态更加模块化并避免样板。6ioyuze24#
下面是我对这个问题的看法:我将该函数作为子模式与useMemo一起使用来创建一个通用的选择器组件:
计数器组件:
用法:
工作示例:CodePen
f0brbegy5#
我已经创建了这个小包react-use-context-selector,它正好完成了这项工作。
我使用了Redux的useSelector中使用的相同方法,它还附带了类型声明,并且返回类型与选择器函数的返回类型相匹配,这使得它适合在TS项目中使用。
vecaoik16#
React 18随附了带有新挂钩
useSyncExternalStore
的外部存储解决方案(Redux或Zustand类方法)。对于React 18:定义
createStore
和useStore
函数:现在使用它:
对于React 17和任何支持挂钩的React版本:
***选项1:**您可以使用外部库(由React团队维护)
use-sync-external-store/shim
:***选项2:**如果您不想添加新库,也不关心并发性问题:
资料来源:
3yhwsihp7#
使用
HoC
和React.memo
防止额外渲染的简单方法:e1xvtsh38#
我做了一个库react-context-slices,它可以解决你所寻找的问题。它的想法是把存储或状态分解成状态片,也就是更小的对象,并为每一个对象创建一个上下文。我告诉你的那个库就是这样做的,它公开了一个函数
createSlice
,它接受一个reducer,初始状态,片的名称,以及创建动作的函数。您可以根据需要创建切片(“todos”、“counter”等),并将它们轻松地集成到一个唯一的接口中,在最后公开两个自定义钩子useValues
和useActions
,它们可以“攻击”所有切片(也就是说,在你的客户端组件中,你不使用useTodosValues
,而是使用useValues
)。关键是useValues
接受切片的名称,所以它等同于redux中的useSelector
。这个库和redux一样使用immer
。它是一个非常小的库,关键是如何使用它。这个函数库只公开了两个函数,createSlice
和composeProviders
。