#javascript #reactjs #use-effect #redux-selector
#javascript #reactjs #использование-эффект #redux-селектор
Вопрос:
Основная проблема: я пытался использовать функцию внутри селектора для повторного преобразования данных и присоединения к другой переменной, в данном случае к моей группе, и объединять их с дочерними элементами в качестве элементов, проблема в том, что функция вызывается каждый раз в бесконечном цикле, несмотря на то, что состояние не изменяется.
У меня есть этот селектор: const groups = useSelector(state => selectProductGroups(state));
И функция такая:
const groups = state.PlatformsReducer.groups;
const items = state.PlatformsReducer.items;
return groups.reduce((ac, g) => {
g.items = items.filter(i => i.groupId == g.productNumber);
if (ac[g.platformId]) {
ac[g.platformId].push(g);
} else {
ac[g.platformId] = [g];
}
return ac;
}, {});
};
So when I use a useEffect to detect if the groups variable has changed the useEffect is triggered in a loop despite the variable groups still empty.
Do you know why? or How to prevent this.
I now the problem is the function in the selector, but I don't know how to prevent this case.
Комментарии:
1. Я думаю, что лучший способ приблизиться к этому — использовать два отдельных
useSelector
в сочетании сuseMemo
пользовательским хуком. Насколько я понимаю, under the hooduseSelector
создает подписку на хранилище, каждый раз, когда хранилище изменяется, оно проверяет, совпадает ли результат предоставленной функции с текущим результатом в состоянии (сравнение ссылок) и обновляет внутренниеuseState
, которые он использует, только если они отличаются. Это означало бы, что он все равно будет запускать вашу сложную функцию каждый раз при изменении хранилища, даже если она не связана с той частью хранилища, которая изменилась.
Ответ №1:
Это связано с тем, что useSelector
хук делает внутри.
useSelector
запускает ваш селектор и проверяет, совпадает ли результат с ранее полученным результатом (сравнение ссылок). Если результаты отличаются, то новый результат сохраняется и выполняется принудительный повторный запуск. Если результаты совпадают, старый результат не заменяется и повторный запуск не запускается.
Это означает, что каждый раз, когда хранилище обновляется, даже если это не связанная часть состояния, ваша сложная функция будет выполняться, чтобы определить, изменился ли результат. В вашем случае это всегда новая ссылка и, следовательно, всегда изменение.
Я думаю, что лучший способ справиться с этим — сделать ваши селекторы как можно более простыми или использовать какую-либо форму более сложной запоминания, например, предоставляемую reselect .
Ниже приведен пример того, как вы могли бы упростить свои селекторы, но при этом получить простой способ повторного использования выбора группы продуктов с помощью пользовательского хука.
const useProductGroups = () => {
// Get groups from the store.
// As the selector does not create a new object it should only
// trigger a rerender when groups changes in the store.
const groups = useSelector(state => state.PlatformsReducer.groups);
// Get items from the store,
// As the selector does not create a new object it should only
// trigger a rerender when items changes in the store.
const items = useSelector(state => state.PlatformsReducer.items);
// Reduce the group collection as desired inside of a useMemo
// so that the reduction only occurs when either items or groups
// changes.
const productGroups = useMemo(() => {
return groups.reduce((ac, g) => {
g.items = items.filter(i => i.groupId == g.productNumber);
if (ac[g.platformId]) {
ac[g.platformId].push(g);
} else {
ac[g.platformId] = [g];
}
return ac;
}, {});
}, [groups, items] /* dependency array on items / groups */);
// return the calculated product groups
return productGroups;
}
Затем вы можете использовать пользовательский хук в своих функциональных компонентах:
const groups = useProductGroups();