重新选择多实例备注

时间:2018-06-25 11:46:15

标签: reactjs redux reselect

我使用React / Redux / Reselect。

reselect doc开始,如果我有多个组件将使用具有不同参数的选择器,则需要为每个实例创建一个。

const makeGetVisibleTodos = () => {
  return createSelector(
    [ 
       (state, props) => props.visibilityFilter, 
       state => state.todos,
    ],
    (visibilityFilter, todos) => {
       return todos.filter(td => td.visibility === visibilityFilter)
      }
    }
  )
}

但是在我的情况下,listId可以来自多个来源(例如props.listIdprops.location.match.listIdprops.location.search.listId等)

所以我更喜欢写以下内容:

const makeGetVisibleTodos = listId => {
  return createSelector(
    [
      state => state.todos,
    ],
    (todos) => {
       todos.filter(td => td.listId === listId)
      }
    }
  )
}

并通过以下方式连接:

  connect(
    (state, ownProps) => ({
      offerer: makeGetVisibleTodos(ownProps.location.match.listId)(state, ownProps),
    }),
  )

我很确定它能正常工作,但我不是100%肯定会正确记住:

如果两个组件使用相同的makeGetVisibleTodos调用listId,它们将具有2个不同的缓存值,对吗?那不是我想要的...

怎么样?

const makeGetVisibleTodos = listId => {
  return createSelector(
    state => state.todos,
    state => listId,
    (todos, listId) => {
       todos.filter(td => td.listId === listId)
      }
    }
  )
}

在这种情况下,当makeGetVisibleTodos(ownProps.listId)时,makeGetVisibleTodos(ownProps.match.params.listId)ownProps.listId === ownProps.match.params.listId是否共享相同的缓存值?

表达问题的另一种方法是:如何传递不(直接)依赖于stateownProps但在记忆过程中是否相等的额外参数?

我还可以扩展ownProps

  connect(
    (state, ownProps) => ({
      offerer: makeGetVisibleTodos()(state, Object.assign({}, ownProps, {listId: ownProps.location.match.listId}),
    }),
  )

但是发现它非常丑陋,这失去了重点...

3 个答案:

答案 0 :(得分:1)

在上面发布的示例中,由于每次调用mapStateToProps函数时都会创建一个重新选择选择器的新实例,因此无法正确地进行记忆。

请注意,在文档中mapStateToProps函数也如何成为工厂函数(makeMapStateToProps),并在返回实际的makeGetVisibleTodos函数之前调用mapStateToProps,就像这样。

const makeMapStateToProps = () => {
  const getVisibleTodos = makeGetVisibleTodos()
  const mapStateToProps = (state, props) => {
    return {
      todos: getVisibleTodos(state, props)
    }
  }
  return mapStateToProps
}

此外,您不会在makeGetVisibleTodos()调用中传递在选择器中使用的道具,而是在实际调用选择器本身时传递。

这将导致类似

const makeGetVisibleTodos = () => {
  return createSelector(
    state => state.todos,
    state => (_, listId), // Here you have access to all the arguments passed
    (todos, listId) => {
       todos.filter(td => td.listId === listId)
      }
    }
  )
}

然后您可以编写如下选择器:

const makeMapStateToProps = () => {
  const getVisibleTodos = makeGetVisibleTodos()
  const mapStateToProps = (state, props) => {

    return {
      todos: getVisibleTodos(state, props.params.match.listId),
      todos2: getVisibleTodos(state, props.listId),
      todos3: getVisibleTodos(state, 'hardcodedListId')
    }
  }
  return mapStateToProps
}

答案 1 :(得分:1)

作为re-reselect(围绕reselect的一个小包装)的作者,我想指出该库如何解决您的用例。

re-reselect提供了一些选择器,这些选择器保留了跨不同组件的存储

import createCachedSelector from 're-reselect';

const getVisibleTodos = createCachedSelector(
  state => state.todos,
  (state, listId) => listId,
  (todos, listId) => {
     todos.filter(td => td.listId === listId)
    }
  }
)(
  (todos, listId) => listId, // Create/use a different selector for each different listId
);

像普通选择器一样使用它(在任何其他容器组件中),而不必考虑选择器工厂:

const makeMapStateToProps = () => {
  const mapStateToProps = (state, props) => {
    return {
      todos: getVisibleTodos(state, props.params.match.listId),
      todos2: getVisibleTodos(state, props.listId),
      todos3: getVisibleTodos(state, 'hardcodedListId')
    }
  }
  return mapStateToProps
}

re-reselect docs中也描述了该用例。

答案 2 :(得分:0)

由于调用makeGetVisibleTodos时总是创建一个新的选择器,因此您的方法无法正确进行记忆。您可以通过写作来改进

const listIdQuerySelector = (state, props) => {
    return props.match.params && props.match.params.listId;
};
const todoSelector = createSelector(
    [
      listIdQuerySelector,
      state => state.todos,
    ],
    (listId, todos) => {
       todos.filter(td => td.listId === listId)
      }
    }
  )

并像使用它

connect(
    (state, ownProps) => ({
      offerer: makeGetVisibleTodos(state, ownProps),
    }),
  )