关于 useSelector 相等性检查
Posted
技术标签:
【中文标题】关于 useSelector 相等性检查【英文标题】:About useSelector equality check 【发布时间】:2020-05-06 02:57:57 【问题描述】:我有一个关于 redux useSelector 相等性检查的问题。
参考 React Redux Hook 文档 (https://react-redux.js.org/api/hooks#equality-comparisons-and-updates)
useSelector 会对返回值和前一个值做引用比较,如果结果看起来不同,则强制重新渲染
我有一个像这样的默认博客商店状态
searcherParam:
keyword: '',
categories: [],
tags: [],
,
在组件中,我使用 useSelector 来检索值
const searchParam = useSelector(state => state.Blog.searcherParam)
如果我调度一个动作来更新具有相同值的 searcherParam,组件将重新渲染,因为返回值是对象(浅比较)
所以我通过多次调用 useSelector 来检索值
const keyword = useSelector(state => state.Blog.searchrParam.keyword)
const categories = useSelector(state => state.Blog.searchrParam.categories)
const tags = useSelector(state => state.Blog.searchrParam.tags)
然后我发送一个操作以再次使用相同的值更新 searcherParam
组件不会重新渲染
我不明白的一点是为什么组件不重新渲染?
如果useSelector做引用比较,分类值(数组)不应该是同一个引用,分派后的标签也是一样
我有什么误解吗?谢谢
不重新渲染的原因是因为我通过useState保存了类别(来自redux store)。
并使用useState的值来调度,所以它是相同的参考......
这里是codeandbox,抱歉Q_Q愚蠢的问题
https://codesandbox.io/s/useselector-test-u6pvg
【问题讨论】:
【参考方案1】:所以当你这样做时:
const newKeyword = useSelector(state => state.Blog.searchrParam.keyword)
const newCategories = useSelector(state => state.Blog.searchrParam.categories)
const newTags = useSelector(state => state.Blog.searchrParam.tags)
这只是意味着,您希望获得它们每个的最新值。
它没有翻译成这个:
searcherParam:
keyword: newKeyword,
categories: newCategories,
tags: newTags,
,
因为searcherParam
在调度操作时将始终是一个新的引用。
如果您只想重新渲染,如果 3 个属性中的任何一个发生更改,那么您可以简单地获取 state.searcherParam
并调度并实现重新渲染。
当您只想在 keyword
更改时重新渲染时,获取单个属性会有所帮助。当cateogories
或tags
发生变化时,您不想重新渲染。
请注意,在这种情况下,如果您只是获取 searcherParam
,它不会关心 3 个属性中的哪一个已更改,您将获得重新渲染,因为它是一个新引用。
这是文档中提到的。
在 cmets 讨论后。
做了一个简单的实现。检查下面
【讨论】:
我知道如果我只是获取 searcherParam,它会重新渲染,因为它是一个新的参考。 我不能理解的一点是分类和标签也是新的参考,为什么组件在调度后不会重新渲染 @Anymore 因此,当您执行state.searcherParam
时,它不会寻找属性更改。它只会重新渲染。如果你已经完成了state.searcherParam.keyword
,那么由于我们已经获取了单个字段值,它只会在关键字更改时重新渲染。
如果你的意思是你说组件不会重新渲染的那部分答案,它会重新渲染,因为searcherParam
永远是一个新的参考,无论其属性如何。
是的,我知道 state.searcherParam.keyword => 只在关键字更改时重新渲染,但是 state.searcherParam.categories 呢?根据我的理解,分类也是一个新的参考,为什么组件不会重新渲染?【参考方案2】:
以上属性不用单独选择,都可以通过解构searchrParam
对象获得:
const newKeyword, newCategories, newTags = useSelector(
state => state.Blog.searchrParam
)
【讨论】:
【参考方案3】:由于您尝试向商店添加相同的值,并且您直接从商店 (state.Blog.searchParam) 引用,因此您下面的代码不会导致重新渲染。
const searchParam = useSelector(state => state.Blog.searcherParam)
为了让它重新渲染,你可以试试下面
const searchParam = useSelector(state => (keyword: state.keyword, categories: state.categories, tags: state.tags))
上面的代码总是会尝试重新渲染,因为返回的对象引用不会相同。
【讨论】:
以上是关于关于 useSelector 相等性检查的主要内容,如果未能解决你的问题,请参考以下文章