重新选择createSelector问题

时间:2018-07-12 09:59:21

标签: javascript reactjs react-native redux reselect

尝试使用Redux的Reselect lib,如下所示:

// 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相当简单的用例?

2 个答案:

答案 0 :(得分:0)

结果是,我错过了createSelector的第二个参数(似乎是必需的):

export const loggedInSelector = createSelector(loggedIn, l => l);

答案 1 :(得分:0)

正如您在自己的答案中指出的那样,您缺少转换功能。

const getLoggedIn = state => state.language.loggedIn
export const getloggedInMemoized = createSelector(loggedIn, i => i)

cannot read property 'language' of undefined错误与您的reducer函数的初始状态有关。

在记住的选择器中,转换函数只是标识函数i => i,它非常有力地表明传入的选择器(const loggedIn = state => state.language.loggedIn)不需要记住。为什么?由于connect中的react-redux将在内部进行自身的相等性检查,以确保仅当一个或多个道具发生更改时才重新渲染组件。

基本上,您最初的loggedIn选择器非常好,并且不需要createSelector的额外开销(无论多么小)。

何时使用createSelector

  1. 无论何时,您都将两个或多个选择器的结果组合在一起,因为createSelector的语法确实有助于构建这些选择器。 例如。

    const taxSelector = createSelector(
      subtotalSelector,
      taxPercentSelector,
      (subtotal, taxPercent) => subtotal * (taxPercent / 100)
    )
    
  2. 无论何时选择器执行的计算量都很大createSelector将确保仅在至少一个输入选择器的结果已更改的情况下才调用transform函数。

  3. 这是我认为微妙但关键的原因。 当返回 选择器的值是arrayobject 。这非常 对性能很重要。 connect的{​​{1}}功能 将对提供的道具执行简单的相等性检查,以查看是否 该组件需要重新渲染(添加时价格昂贵)。 例如。

    react-redux

    每次调用const getSaleItems = state => { const items = getShopItems(state) return items.filter(i => i.isOnSale) } 时,它将返回一个新数组。甚至 如果getSaleItems返回的数组未更改。这表示 getShopItems将重新渲染该组件,因为 对道具进行浅薄的平等检查,前提是它会发现 数组已更改。

    另一方面,使用react-redux时:

    createSelector

    如果const getSaleItems = createSelector( getShopItems, items => items.filter(i => i.isOnSale) } 的结果未更改,则对getShopItems的连续调用将返回相同的数组实例,因为结果已被记忆。这意味着浅层相等性检查 getSaleItems的人将看到没有任何变化,并且确实 不需要重新渲染组件。