restate / v1.0.0

Subskrybuj tylko to, czego potrzebujesz

Wybierz, od której części magazynu zależy każdy komponent, porównuj obiekty przez shallow, grupuj zmiany przez batch i podłączaj zdarzenia zewnętrzne.

Na tej stroniePrzekaż selectorWypróbujWybieraj kilka pól przez shallowNapisz własne porównanieGrupuj zmiany przez batchSubskrybuj poza ReactPodłącz zdarzenia zewnętrzne

Przekaż selector

Wywołaj hook z funkcją, która wybiera to, czego potrzebuje komponent. Po każdej zmianie restate uruchamia selector i porównuje wynik z poprzednim przez Object.is. Jeśli są równe, komponent się nie renderuje.

Kartka się zmienia. Czy ItemCount się wyrenderuje?

Nie. Jego selector wciąż zwraca tę samą liczbę produktów, więc wybór jest równy i React nie jest proszony o render.

JavaScript / JSX
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>;
}

Wypróbuj

Zmieniaj pola i obserwuj liczniki renderowań. Wyłącz shallow, by zobaczyć selector, który za każdym razem zwraca nowy obiekt.

Przygotowywanie przykładu…

Wybieraj kilka pól przez shallow

Jeśli selector buduje obiekt, za każdym razem zwraca nowy, więc Object.is zawsze widzi zmianę. Przekaż shallow jako drugi argument: porównuje własne pola obiektu na jednym poziomie głębokości.

shallow porównuje na jednym poziomie także elementy tablic, Map i Set.

JavaScript / JSX
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>
  );
}

Napisz własne porównanie

Jako drugi argument nada się dowolna funkcja (left, right) => boolean. Użyj jej, gdy shallow nie wystarcza, na przykład do porównania listy po id.

JavaScript / JSX
const ids = useCart(
  (cart) => cart.items.map((item) => item.id),
  (left, right) => left.length === right.length && left.every((id, index) => id === right[index]),
);

Grupuj zmiany przez batch

Każde set od razu powiadamia subskrybentów. Gdy jedna akcja zmienia kilka magazynów, owiń ją w batch: pamięć aktualizuje się od razu, a subskrybenci uruchamiają się raz po callbacku.

JavaScript / JSX
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.
}

Subskrybuj poza React

subscribeSelector wywołuje cię tylko wtedy, gdy zmienia się wybrana wartość, z tą samą opcjonalną funkcją porównania.

JavaScript / JSX
const stop = useCart.subscribeSelector(
  (cart) => cart.items.length,
  (count, previous) => analytics.track('cart-size', { count, previous }),
);

Podłącz zdarzenia zewnętrzne

Drugim argumentem restate może być updater. Startuje, gdy pierwszy komponent lub subskrybent zaczyna nasłuchiwać, a jego sprzątanie uruchamia się, gdy przestaje ostatni, więc zdarzenia przeglądarki, gniazda czy czujniki są podłączone tylko wtedy, gdy są potrzebne.

Użyj start() i stop(), by sterować nim ręcznie.

JavaScript / JSX
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);
  };
});

Szukaj w dokumentacji

Przeszukuj tytuły, opisy i treść wszystkich przewodników.