代码之家  ›  专栏  ›  技术社区  ›  Augustin Riedinger

重新选择多实例备忘录

  •  1
  • Augustin Riedinger  · 技术社区  · 6 年前

    我使用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.listId 我是说, props.location.match.listId 我是说, props.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 用同样的方法 列表ID ,它们将有两个不同的缓存值,对吗?这不是我想要的…

    这个怎么样?

    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 是吗?

    或者另一种方法来解决这个问题是:如何传递不直接依赖的额外参数。 state ownProps 但是在写回忆录时是否检查了平等?

    我也可以延长 所有权 以下内容:

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

    但发现它超级丑陋,它失去了重点…

    3 回复  |  直到 6 年前
        1
  •  1
  •   Niekert    6 年前

    在上面发布的示例中,由于每次 mapStateToProps 函数被调用。

    注意文档中 地图状态 函数也成为工厂函数( makeMapStateToProps ) makeGetVisibleTodos 在返回实际值之前调用 地图状态 功能,就像这样。

    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
    }
    
        2
  •  1
  •   Andrea Carraro    6 年前

    作为 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 是的。

        3
  •  0
  •   Shubham Khatri    6 年前

    你的方法不会正确地进行记忆,因为当你调用 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),
        }),
      )
    
    推荐文章