restate / v1.0.0
Абонирайте се само за нужното
Изберете от коя част на store зависи всеки компонент, сравнявайте обекти чрез shallow, групирайте промени чрез batch и свързвайте външни събития.
На тази страница
Подайте selectorОпитайтеИзбор на няколко полета чрез shallowСобствено сравнениеГрупиране на промени чрез batchАбониране извън ReactСвързване на външни събитияПодайте selector
Извикайте hook с функция, която избира нужното на компонента. След всяка промяна restate изпълнява selector и сравнява резултата с предишния чрез Object.is. Ако са равни, компонентът не се пререндерира.
Картичката се променя. Пререндерира ли се ItemCount?
Не. Неговият selector продължава да връща същия брой артикули, така че изборът е същият и React не е помолен да го пререндерира.
const useCart = restate({ items: ['Book'], coupon: '', note: '' });
function ItemCount() {
// Re-renders only when the number of items changes.
const count = useCart((cart) => cart.items.length);
return <p>{count} items</p>;
}Опитайте
Променяйте полетата и следете броячите на рендери. Изключете shallow, за да видите selector, който всеки път връща нов обект.
Подготовка на примера…
Избор на няколко полета чрез shallow
Ако selector сглобява обект, всеки път връща нов, затова Object.is винаги вижда промяна. Подайте shallow като втори аргумент: той сравнява собствените полета на обекта на едно ниво дълбочина.
shallow сравнява на едно ниво и елементите на масиви, Map и Set.
import { restate, shallow } from '@kkwaenggwari/restate';
function CartSummary() {
const { count, coupon } = useCart(
(cart) => ({ count: cart.items.length, coupon: cart.coupon }),
shallow,
);
return (
<p>
{count} items · {coupon || 'no coupon'}
</p>
);
}Собствено сравнение
Като втори аргумент става всяка функция (left, right) => boolean. Използвайте я, когато shallow не стига, например за сравняване на списък по id.
const ids = useCart(
(cart) => cart.items.map((item) => item.id),
(left, right) => left.length === right.length && left.every((id, index) => id === right[index]),
);Групиране на промени чрез batch
Всяко set веднага известява абонатите. Когато едно действие променя няколко store, обвийте го в batch: паметта се обновява веднага, а абонатите се изпълняват веднъж след callback.
import { batch } from '@kkwaenggwari/restate';
function checkout() {
batch(() => {
useCart.set((cart) => ({ ...cart, items: [] }));
useOrder.set((order) => ({ ...order, status: 'paid' }));
});
// Subscribers run once, after both stores changed.
}Абониране извън React
subscribeSelector ви извиква само когато избраната стойност се промени, със същата незадължителна функция за сравнение.
const stop = useCart.subscribeSelector(
(cart) => cart.items.length,
(count, previous) => analytics.track('cart-size', { count, previous }),
);Свързване на външни събития
Вторият аргумент на restate може да е updater. Той стартира, когато първият компонент или абонат започне да слуша, а почистването му се изпълнява, когато спре последният, така че събития на браузъра, сокети или сензори са свързани само докато са нужни.
Използвайте start() и stop() за ръчно управление.
import { restate } from '@kkwaenggwari/restate';
// Listens while at least one component or subscriber uses the store.
export const useOnline = restate(true, ({ setState }) => {
const update = () => setState(navigator.onLine);
window.addEventListener('online', update);
window.addEventListener('offline', update);
update();
return () => {
window.removeEventListener('online', update);
window.removeEventListener('offline', update);
};
});