奇怪的重新选择选择器行为
Weird Reselect selector behavior
出于某种原因,我的 selector
函数仅在其中一个参数发生变化而不是另一个参数发生变化时被调用。
这是我的 selector
从 state
获取 transactions
并对其应用 2 个过滤器
export const getFilteredTransactionsSelector = createSelector(
(state) => state.transactions.transactions,
(items) =>
memoize((filterValueFirst, filterValueSecond) =>
items
.filter((item) => {
if (filterValueFirst === "Show All") {
return true;
}
return item["Status"] === filterValueFirst;
})
.filter((item) => {
if (filterValueSecond === "Show All") {
return true;
}
return item["Type"] === filterValueSecond;
})
)
);
在我的组件 mapStateToProps
中,我将当前状态传递给 selector
const mapStateToProps = (state) => ({
transactions: getTransactions(state),
getFilteredTransactions: getFilteredTransactionsSelector(state),
...
});
然后我会在其中一个过滤器值发生变化时调用它
useEffect(() => {
setFilteredTransactions(
getFilteredTransactions(statusFilterValue, typeFilterValue)
);
}, [transactions, statusFilterValue, typeFilterValue]);
问题是只有当我更改第一个过滤器的值 (statusFilterValue
) 时,我才会得到过滤后的数据。如果我更改第二个,尽管 useEffect
挂钩按应有的方式被调用,但什么也没有发生。
如果我将 console.log
放在 memoize
函数中,它只会在我更改第一个过滤器而不是第二个过滤器时显示结果。任何帮助将不胜感激
从你问题中的代码来看,你根本不需要记忆。如果您确实需要它,那么最好使用已经在重新选择中的那个,并防止添加不必要的依赖项。
您也不需要效果,因为只要项目、filterValueFirst 或 filterValueSecond 不会改变,selectFilteredTransactions returns 就不会改变,如果 setFilteredTransactions 来自 useState,则将相同的值传递给它渲染不会导致任何重新渲染。
您可以像这样创建选择器:
export const selectFilteredTransactions = createSelector(
(state) => state.transactions.transactions,
(a, filterValueFirst) => filterValueFirst,
(a, b, filterValueSecond) => filterValueSecond,
(items, filterValueFirst, filterValueSecond) =>
console.log('running selector, something changed') ||
items
.filter((item) => {
if (filterValueFirst === 'Show All') {
return true;
}
return item['Status'] === filterValueFirst;
})
.filter((item) => {
if (filterValueSecond === 'Show All') {
return true;
}
return item['Type'] === filterValueSecond;
})
);
并这样称呼它:
//don't even need the effect here since filteredTransactions
// only changes when items, filterValueFirst or filterValueSecond
// changes
setFilteredTransactions(//assuming this comes from useState
useSelector((state) =>
selectFilteredTransactions(
state,
statusFilterValue,
typeFilterValue
)
)
);
出于某种原因,我的 selector
函数仅在其中一个参数发生变化而不是另一个参数发生变化时被调用。
这是我的 selector
从 state
获取 transactions
并对其应用 2 个过滤器
export const getFilteredTransactionsSelector = createSelector(
(state) => state.transactions.transactions,
(items) =>
memoize((filterValueFirst, filterValueSecond) =>
items
.filter((item) => {
if (filterValueFirst === "Show All") {
return true;
}
return item["Status"] === filterValueFirst;
})
.filter((item) => {
if (filterValueSecond === "Show All") {
return true;
}
return item["Type"] === filterValueSecond;
})
)
);
在我的组件 mapStateToProps
中,我将当前状态传递给 selector
const mapStateToProps = (state) => ({
transactions: getTransactions(state),
getFilteredTransactions: getFilteredTransactionsSelector(state),
...
});
然后我会在其中一个过滤器值发生变化时调用它
useEffect(() => {
setFilteredTransactions(
getFilteredTransactions(statusFilterValue, typeFilterValue)
);
}, [transactions, statusFilterValue, typeFilterValue]);
问题是只有当我更改第一个过滤器的值 (statusFilterValue
) 时,我才会得到过滤后的数据。如果我更改第二个,尽管 useEffect
挂钩按应有的方式被调用,但什么也没有发生。
如果我将 console.log
放在 memoize
函数中,它只会在我更改第一个过滤器而不是第二个过滤器时显示结果。任何帮助将不胜感激
从你问题中的代码来看,你根本不需要记忆。如果您确实需要它,那么最好使用已经在重新选择中的那个,并防止添加不必要的依赖项。
您也不需要效果,因为只要项目、filterValueFirst 或 filterValueSecond 不会改变,selectFilteredTransactions returns 就不会改变,如果 setFilteredTransactions 来自 useState,则将相同的值传递给它渲染不会导致任何重新渲染。
您可以像这样创建选择器:
export const selectFilteredTransactions = createSelector(
(state) => state.transactions.transactions,
(a, filterValueFirst) => filterValueFirst,
(a, b, filterValueSecond) => filterValueSecond,
(items, filterValueFirst, filterValueSecond) =>
console.log('running selector, something changed') ||
items
.filter((item) => {
if (filterValueFirst === 'Show All') {
return true;
}
return item['Status'] === filterValueFirst;
})
.filter((item) => {
if (filterValueSecond === 'Show All') {
return true;
}
return item['Type'] === filterValueSecond;
})
);
并这样称呼它:
//don't even need the effect here since filteredTransactions
// only changes when items, filterValueFirst or filterValueSecond
// changes
setFilteredTransactions(//assuming this comes from useState
useSelector((state) =>
selectFilteredTransactions(
state,
statusFilterValue,
typeFilterValue
)
)
);