[英]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.