簡體   English   中英

重新選擇將無法正確記憶同一組件的多個實例

[英]Reselect will not correctly memoize with multiple instances of the same component

我正在閱讀Redux的文檔並且遇到了reselect 下面的代碼創建了一個選擇器和文件說,如果我們想用它兩個VisibleTodoList組件那么它將無法正常工作。

import { createSelector } from 'reselect'

const getVisibilityFilter = (state, props) => state.todoLists[props.listId].visibilityFilter

const getTodos = (state, props) => state.todoLists[props.listId].todos

const getVisibleTodos = createSelector([getVisibilityFilter, getTodos], (visibilityFilter, todos) => {
  switch (visibilityFilter) {
    case 'SHOW_COMPLETED':
      return todos.filter(todo => todo.completed)
    case 'SHOW_ACTIVE':
      return todos.filter(todo => !todo.completed)
    default:
      return todos
  }
})

export default getVisibleTodos

將getVisibleTodos選擇器與visibleTodoList容器的多個實例一起使用將無法正確地進行memoize

const mapStateToProps = (state, props) => {
  return {
     // WARNING: THE FOLLOWING SELECTOR DOES NOT CORRECTLY MEMOIZE
     todos: getVisibleTodos(state, props)
  }
}

這是什么意思? 我無法弄清楚為什么它不起作用。

正確。 那是因為默認情況下重新選擇只記憶最新的輸入集:

const a = someSelector(state, 1); // first call, not memoized
const b = someSelector(state, 1); // same inputs, memoized
const c = someSelector(state, 2); // different inputs, not memoized
const d = someSelector(state, 1); // different inputs from last time, not memoized

在這些情況下,選擇器仍然會檢索數據,它只需要重新計算結果,即使它在過去的某個時刻看到了輸入。

因此,如果您在mapState函數中使用選擇器,並且它引用了ownProps的值,那么該組件的多個實例可能會導致選擇器永遠不會正確地進行memoize

const mapState = (state, ownProps) => {
    const item = selectItemForThisComponent(state, ownProps.itemId);

    return {item};
}


// later
<SomeComponent itemId={1} />
<SomeComponent itemId={2} />

在該示例中, selectItemForThisComponent將始終與(state, 1)(state, 2)背靠背調用,因此它將不會正確地進行memoize。

一種解決方案是使用connect支持的“工廠函數”語法。 如果你的mapState函數在第一次調用時返回一個函數, connect會將其用作真正的mapState實現。 這樣,您可以為每個組件實例創建唯一的選擇器:

const makeUniqueSelectorInstance = () => createSelector(
    [selectItems, selectItemId],
    (items, itemId) => items[itemId]
);    


const makeMapState = (state) => {
    const selectItemForThisComponent = makeUniqueSelectorInstance();

    return function realMapState(state, ownProps) {
        const item = selectItemForThisComponent(state, ownProps.itemId);

        return {item};
    }
}

export default connect(makeMapState)(SomeComponent);

組件1和組件2都將獲得它們自己的selectItemForThisComponent的唯一副本,並且每個副本將通過一致的可重復輸入進行調用,從而允許正確的memoization。

更新

我在我的博客文章Idiomatic Redux中擴展了這個答案:使用Reselect Selectors進行性能和封裝

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM