关于 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 更改时重新渲染时,获取单个属性会有所帮助。当cateogoriestags 发生变化时,您不想重新渲染。

请注意,在这种情况下,如果您只是获取 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 相等性检查的主要内容,如果未能解决你的问题,请参考以下文章

检查两个数组之间的相等性[重复]

带有类型检查的Scala相等性?

如何检查排列是不是具有相等的奇偶性?

如何使用 cypress 检查元素内部文本的相等性?

检查接口的相等性

如何检查NaN javascript的相等性[重复]