Найти в Дзене

Мемоизация селекторов в Zustand


Если вы используете Zustand, то знаете, что computed значения реализуются с помощью селекторов.

const userPrs = useChartsStore((state) => {
return state.pullRequests.filter(pr => pr.author.id === state.user.id);
});

В примере выше:

- при каждом обновлении стейта значение селектора будет вычисляться заново
- это приведёт к ре-рендеру компонента, так как каждый раз мы постоянно возвращает новый массив по ссылке, а по-умолчанию используется строгое сравнение (old === new).

Чтобы решить эту проблему в Zustand есть хук useShallow , который сделает “поверхностное” сравнение предыдущего и нового значения. Если они равны — ре-рендер не произойдёт.

const userPrs = useChartsStore(useShallow((state) => {
return state.pullRequests.filter(pr => pr.author.id === state.user.id);
}));

Но при этом селектор всё равно выполнится, и в большинстве случаев нам не нужно об этом заботиться. Проблема появляется если выполнение селектора занимает много времени или же он вызывается много раз в различных компонентах или других селекторах.

Автор Zustand упоминает, что можно нарушить согласованность данных и просто положить вычисляемые данные в стейт (но в этом случае нужно вручную следить за их актуальностью).

Также он отмечает, что для этих целей можно использовать метод memoize из его библиотеки proxy-memoize (для redux есть reselect).

Аналогично immer’у proxy-memoize работает на основе Proxy. memoize запоминает предыдущий параметр функции и свойства к которым обращались в селекторе (для этого и нужен Proxy). При следующем выполнении функции, он проверит изменились ли используемые свойства, если нет — вернёт значение, вычисленное в прошлый раз.

const authorSelector = memoize((state) => state.pullRequests.filter(pr => pr.author.id === state.user.id));

const userPrs = useChartsStore(authorSelector);

Конечно, нужно помнить, что мемоизировать можно только “чистую” функцию — если она возвращает одни и те же значения в ответ на одни и те же аргументы

Так, обернув пару селекторов в memoize, я ускорил фильтрацию пул-реквестов в более чем 20 раз (900мс ⇒ 40мс).

#react #zustand #statemanagement #frontend
Мемоизация селекторов в Zustand  Если вы используете Zustand, то знаете, что computed значения реализуются с помощью селекторов.  const userPrs = useChartsStore((state) => { return state.pullRequests.
1 минута