重新选择 createSelector 问题
尝试使用 Redux 的 Reselect 库,如下所示:
// selectors.js
import { createSelector } from "reselect";
const loggedIn = state => {
return state.language.loggedIn;
};
export const loggedInSelector = createSelector(loggedIn);
用法如下:
import React from "react";
import { connect } from "react-redux";
import { Text, View } from "react-native";
import { loggedInSelector } from "./../lib/selectors/language";
const Foo = ({ loggedIn }) => {
return (
<View>
<Text>Foo - {loggedIn ? "logged in" : "not logged in"}</Text>
</View>
);
};
export default connect(state => {
console.log(state);
const loggedIn = loggedInSelector(state);
return {
loggedIn
};
})(Foo);
console.log(state)
的结果是:
language: {
loggedIn: false
}
但是,我收到类型错误:无法读取未定义的属性“语言”。有人能看出我在这个我认为相当简单的 Reselect 用例中哪里出错了吗?
正如您在自己的回答中指出的那样,您缺少转换函数。
const getLoggedIn = state => state.language.loggedIn
export const getloggedInMemoized = createSelector(loggedIn, i => i)
无法读取未定义的属性“语言”
错误与您的 Reducer 函数的初始状态有关。
在您的记忆选择器中,转换函数只是身份函数
i => i
,这是一个非常强烈的指标,表明您传入的选择器 (
const logstIn = state => state.language.loggedIn
) 不需要记忆。为什么?因为
react-redux
的
connect
会在内部进行自己的相等性检查,以确保只有当一个或多个 props 发生变化时,才会重新渲染组件。
基本上,您的初始
loggedIn
选择器完全没问题,并且不需要
createSelector
的额外开销(无论多小)。
何时使用
createSelector
?
-
任何时候您组合两个或多个选择器的结果 ,因为
createSelector
的语法确实有助于构建这些选择器。 例如。const taxSelector = createSelector( subtotalSelector, taxPercentSelector, (subtotal, taxPercent) => subtotal * (taxPercent / 100) )
-
任何时候选择器执行计算量大的操作时 。
createSelector
将确保仅当至少一个输入选择器的结果发生变化时才调用转换函数。 -
在我看来,这是微妙但关键的原因。 当选择器的返回值是
数组
或对象
时。这对于性能非常重要。react-redux
的connect
函数将对提供的 props 执行简单的相等性检查,以查看组件是否需要重新渲染(加起来很昂贵)。例如。const getSaleItems = state => { const items = getShopItems(state) return items.filter(i => i.isOnSale) }
每次调用
getSaleItems
时,它都会返回一个新数组。即使getShopItems
返回的数组没有改变。这意味着react-redux
将重新渲染组件,因为当它对提供的 props 进行浅层相等性检查时,它将看到 数组已更改。另一方面,当使用
createSelector
时:const getSaleItems = createSelector( getShopItems, items => items.filter(i => i.isOnSale) }
如果
getShopItems
的结果没有改变,则对getSaleItems
的连续调用将返回相同的数组实例,因为结果已被记忆。这意味着react-redux
的浅层相等性检查将发现没有任何变化,并且它不需要重新渲染组件🎉。
结果发现,我缺少
createSelector
的(看似必需的)第二个参数:
export const logstedInSelector = createSelector(loggedIn, l => l);