使用reselect createSelector在redux store中选择相互依赖的数据

时间:2018-05-05 09:52:15

标签: redux react-redux reselect

所以,我正在使用reduxreselect工具createSelectormapStateToProps中记住我的选择器,这很棒。

现在,我的商店中有一些标准化数据,以及需要来自商店的相互依赖数据的容器。

我现在正在这样做,并且它有效:

const getItemId = props => parseInt(props.match.params.itemId, 10)

const containerSelector = createSelector(getItemId, itemId =>
  createSelector(
    [getUser, getItem(itemId)],
    (user, item) =>
      createSelector(
        [
          getFoo(item.fooId),
          getBar(item.barId)
        ],
        (foo, bar) => ({ user, item, foo, bar })
      )
  )
)

const mapStateToProps = (state, ownProps) =>
  containerSelector(ownProps)(state)(state)

export default connect(mapStateToProps)(Container)

问题:有更好的方法吗?

  1. 更具可读性?
  2. 更好的练习?
  3. 性能更高? (这是表演者吗?)
  4. 修改

    感谢Tho Vu的回答,我可以简化并记忆,就像这样:

    import { getUser, getItemById, getFooById } from 'selectors'
    
    // Note: getStuffById are selector factories like: 
    //   const getStuffById = id => state => state.stuff.objects[id] 
    
    const itemIdSelector = (_, props) => parseInt(props.match.params.itemId, 10)
    
    const itemSelector = (state, props) => {
       const itemId = itemIdSelector(state, props)
       return getItemById(itemId)(state)
    }
    
    const fooSelector = (state, props) => {
       const item = itemSelector(state, props)
       return item ? getFooById(item.fooId)(state) : null
    }
    
    const mapStateToProps = createStructuredSelector({ 
      user: getUser, 
      itemId: itemIdSelector, 
      item: itemSelector,
      foo: fooSelector
    })
    

    但我仍然喜欢它吗?或者它已经好了吗?

1 个答案:

答案 0 :(得分:1)

来自reselect的文档:

  

当选择器连接到带连接的组件时,   组件道具作为第二个参数传递给选择器

因此,用于获取createSelector的第一个itemId图层实际上是不必要的,您可以将其替换为:

const getItem = (state, props) => {
   const itemId = parseInt(props.match.params.itemId, 10)
   return getItem(itemId)
}

其次,createSelector具有以下属性:

  

使用createSelector创建的选择器的缓存大小为1.这   意味着它们总是在输入选择器的值时重新计算   更改,因为选择器只存储每个的前一个值   输入选择器。

这意味着您的自定义选择器会在useritemIditemfoobar的每次更改时重新计算。关于其他输入选择器很难说,但我没有看到user和其他人之间的任何关系。因此,您应该仅为user创建单独的选择器。

此外,createSelector的目的是创建一个具有可保留memoization的选择器,因此以您的方式嵌套它们将导致每次外部重新计算时都会重新创建内部选择器。

我通常做的就是像这样压扁它们:

const getItem = (state, props) => {
   const itemId = parseInt(props.match.params.itemId, 10)
   return getItem(itemId)
}

const userSelector = createSelector(getUser, user => user)
const itemSelector = createSelector(getItem, item => item)

foobar更加困难,因为在您的代码中,选择器会查找itemitem.fooIdfoo中的更改,但也会重新计算。我们仍然需要嵌套选择器,但需要分离foobar

const fooFromItemSelector = createSelector(itemSelector, item => getFoo(item.fooId))
const fooSelector = createSelector(fooFromItemSelector, foo => foo)

同样适用于bar

最后,您需要将它们组合在一起以创建containerSelector

import { createStructuredSelector } from 'reselect'

const containerSelector = createStructuredSelector({
    user: userSelector,
    item: itemSelector,
    foo: fooSelector,
    bar: barSelector
})