restate / v1.0.0
Abonați-vă doar la ce vă trebuie
Alegeți de ce parte a store-ului depinde fiecare componentă, comparați obiecte cu shallow, grupați modificările cu batch și conectați evenimente externe.
Pe această pagină
Dați un selectorÎncercațiSelectarea mai multor câmpuri cu shallowComparație proprieGruparea modificărilor cu batchAbonare în afara ReactConectarea evenimentelor externeDați un selector
Apelați hook-ul cu o funcție care alege ce îi trebuie componentei. După fiecare schimbare, restate rulează selectorul și compară rezultatul cu cel anterior prin Object.is. Dacă sunt egale, componenta nu se randează.
Cardul se schimbă. Se randează ItemCount?
Nu. Funcția selector a lui returnează în continuare același număr de produse, deci selecția e egală și React nu e rugat să randeze.
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>;
}Încercați
Schimbați câmpuri și urmăriți contoarele de randare. Dezactivați shallow ca să vedeți un selector care returnează un obiect nou de fiecare dată.
Se pregătește exemplul…
Selectarea mai multor câmpuri cu shallow
Când un selector construiește un obiect, returnează unul nou de fiecare dată, așa că Object.is vede mereu o schimbare. Dați shallow ca al doilea argument: compară câmpurile proprii ale obiectului la un nivel de adâncime.
shallow compară și elementele tablourilor, Map-urilor și Set-urilor la un nivel de adâncime.
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>
);
}Comparație proprie
Orice funcție (left, right) => boolean merge ca al doilea argument. Folosiți-o când shallow nu ajunge, de exemplu pentru a compara o listă după id.
const ids = useCart(
(cart) => cart.items.map((item) => item.id),
(left, right) => left.length === right.length && left.every((id, index) => id === right[index]),
);Gruparea modificărilor cu batch
Fiecare set notifică imediat abonații. Când o acțiune schimbă mai multe store-uri, înfășurați-o în batch: memoria se actualizează imediat, iar abonații rulează o dată după 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.
}Abonare în afara React
subscribeSelector vă apelează doar când se schimbă valoarea selectată, cu aceeași funcție opțională de comparare.
const stop = useCart.subscribeSelector(
(cart) => cart.items.length,
(count, previous) => analytics.track('cart-size', { count, previous }),
);Conectarea evenimentelor externe
Al doilea argument al lui restate poate fi un updater. Rulează când prima componentă sau primul abonat începe să asculte, iar curățarea lui rulează când se oprește ultimul, așa că evenimentele browserului, socket-urile sau senzorii sunt conectate doar cât e nevoie.
Pentru control manual folosiți start() și 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);
};
});