restate / v1.0.0
Підписуйтеся лише на потрібне
Обирайте, від якої частини сховища залежить кожен компонент, порівнюйте об’єкти через shallow, групуйте зміни через batch і підключайте зовнішні події.
На цій сторінці
Передайте selectorСпробуйтеВибір кількох полів через shallowВласна функція порівнянняГрупування змін через batchПідписка поза ReactПідключення зовнішніх подійПередайте selector
Викличте хук із функцією, що вибирає те, що потрібно компоненту. Після кожної зміни 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 одразу сповіщає підписників. Коли одна дія змінює кілька сховищ, обгорніть її в batch: пам’ять оновлюється одразу, а підписники спрацьовують один раз після колбека.
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);
};
});