React ve React Native için durum · 1.0

Durumu paylaşın.Tek hook.Bu kadar.

Store'u tek satırda bildirin ve herhangi bir bileşende kullanın; Provider, action ve reducer olmadan. Bileşen yalnızca seçtiği değer değiştiğinde yeniden render edilir, kaydetme ise siz karar verdiğinizde olur.

Terminal
npm install @kkwaenggwari/restate

Canlı — gerçek bir restate store'u

useCart.set(cart => ({ ...cart, items: cart.items + 1, total: cart.total + 12 }))

items ve total değişir: üç kart render edilir, hediye kartı yerinde kalır.

01 — Basit

Aynı özellik, daha az kavram.

Aynı işin dört uygulaması yan yana. Sayılar burada gösterilen koddan gelir ve bu site derlenirken ölçülür.

Paylaşılan sayaç

İki bileşen aynı sayıyı okur ve günceller.

Redux Toolkit Güncellemeleri, React context ile sağlanan bir store'a gönderilen slice ve action'lar olarak düzenler. Mükemmel DevTools ve büyük ekipler için katı, öngörülebilir bir güncelleme akışı.

Zustand create() ile bir store hook'u oluşturur ve setState ile değiştirir. Minik ve esnek; kalıcılık ve DevTools için middleware'leri var.

Jotai Atom'ları ve türetilmiş atom'ları birleştirir, isteğe bağlı olarak bir Provider içinde. Birçok küçük durum parçası arasında ince taneli bağımlılıklar.

Redux Toolkit29 satır · 5 API
JavaScript / JSX
import { configureStore, createSlice } from '@reduxjs/toolkit';
import { Provider, useDispatch, useSelector } from 'react-redux';

const slice = createSlice({
  name: 'count',
  initialState: 0,
  reducers: { increment: (count) => count + 1 },
});
const store = configureStore({
  reducer: { count: slice.reducer },
});

function Counter() {
  const count = useSelector((state) => state.count);
  const dispatch = useDispatch();
  return <button onClick={() => dispatch(slice.actions.increment())}>{count}</button>;
}

export default function App() {
  return (
    <Provider store={store}>
      <Counter />
      <Counter />
    </Provider>
  );
}
Zustand16 satır · 1 API
JavaScript / JSX
import { create } from 'zustand';

const useCount = create(() => ({ count: 0 }));
const increment = () =>
  useCount.setState((s) => ({
    count: s.count + 1,
  }));

function Counter() {
  const count = useCount((s) => s.count);
  return <button onClick={increment}>{count}</button>;
}

export default function App() {
  return (
    <>
      <Counter />
      <Counter />
    </>
  );
}
Jotai13 satır · 2 API
JavaScript / JSX
import { atom, useAtom } from 'jotai';

const countAtom = atom(0);

function Counter() {
  const [count, setCount] = useAtom(countAtom);
  return <button onClick={() => setCount((n) => n + 1)}>{count}</button>;
}

export default function App() {
  return (
    <>
      <Counter />
      <Counter />
    </>
  );
}

restate Tek bir bildirim hem store hem hook'tur.

restate13 satır · 1 API
JavaScript / JSX
import { restate } from '@kkwaenggwari/restate';

const useCount = restate(0);

function Counter() {
  const count = useCount();
  return <button onClick={() => useCount.set((n) => n + 1)}>{count}</button>;
}

export default function App() {
  return (
    <>
      <Counter />
      <Counter />
    </>
  );
}

Bu iş için Zustand ve Jotai de küçüktür ve Provider gerektirmez. Kaydetme ve belge başına durum eklendikçe fark büyür.

Alan seçme

Yalnızca metin değiştiğinde başlık bileşeni render edilmemeli.

Redux Toolkit Güncellemeleri, React context ile sağlanan bir store'a gönderilen slice ve action'lar olarak düzenler. Mükemmel DevTools ve büyük ekipler için katı, öngörülebilir bir güncelleme akışı.

Zustand create() ile bir store hook'u oluşturur ve setState ile değiştirir. Minik ve esnek; kalıcılık ve DevTools için middleware'leri var.

Jotai Atom'ları ve türetilmiş atom'ları birleştirir, isteğe bağlı olarak bir Provider içinde. Birçok küçük durum parçası arasında ince taneli bağımlılıklar.

Redux Toolkit26 satır · 4 API
JavaScript / JSX
import { configureStore, createSlice } from '@reduxjs/toolkit';
import { Provider, useSelector } from 'react-redux';

const article = createSlice({
  name: 'article',
  initialState: { title: 'Hello', body: '' },
  reducers: {
    editBody: (i) => {
      i.body += '!';
    },
    editTitle: (i) => {
      i.title += '!';
    },
  },
});
const store = configureStore({ reducer: article.reducer });

function Title() {
  const title = useSelector((i) => i.title);
  return <h3>{title}</h3>;
}

export default function App() {
  return (
    <Provider store={store}>
      <Title />
      <button onClick={() => store.dispatch(article.actions.editBody())}>body + !</button>
      <button onClick={() => store.dispatch(article.actions.editTitle())}>title + !</button>
    </Provider>
  );
}
Zustand17 satır · 1 API
JavaScript / JSX
import { create } from 'zustand';

const useArticle = create(() => ({ title: 'Hello', body: '' }));

function Title() {
  const title = useArticle((i) => i.title);
  return <h3>{title}</h3>;
}

export default function App() {
  return (
    <>
      <Title />
      <button
        onClick={() =>
          useArticle.setState((i) => ({
            body: i.body + '!',
          }))
        }
      >
        body + !
      </button>
      <button
        onClick={() =>
          useArticle.setState((i) => ({
            title: i.title + '!',
          }))
        }
      >
        title + !
      </button>
    </>
  );
}
Jotai19 satır · 3 API
JavaScript / JSX
import { atom, useAtomValue, useSetAtom } from 'jotai';

const articleAtom = atom({ title: 'Hello', body: '' });
const titleAtom = atom((get) => get(articleAtom).title);

function Title() {
  const title = useAtomValue(titleAtom);
  return <h3>{title}</h3>;
}

export default function App() {
  const setArticle = useSetAtom(articleAtom);
  return (
    <>
      <Title />
      <button
        onClick={() =>
          setArticle((i) => ({
            ...i,
            body: i.body + '!',
          }))
        }
      >
        body + !
      </button>
      <button
        onClick={() =>
          setArticle((i) => ({
            ...i,
            title: i.title + '!',
          }))
        }
      >
        title + !
      </button>
    </>
  );
}

restate Zaten kullandığınız hook'a bir selector verin.

restate17 satır · 1 API
JavaScript / JSX
import { restate } from '@kkwaenggwari/restate';

const useArticle = restate({ title: 'Hello', body: '' });

function Title() {
  const title = useArticle((i) => i.title);
  return <h3>{title}</h3>;
}

export default function App() {
  return (
    <>
      <Title />
      <button
        onClick={() =>
          useArticle.set((i) => ({
            ...i,
            body: i.body + '!',
          }))
        }
      >
        body + !
      </button>
      <button
        onClick={() =>
          useArticle.set((i) => ({
            ...i,
            title: i.title + '!',
          }))
        }
      >
        title + !
      </button>
    </>
  );
}

Buradaki tüm araçlar seçim yapabilir. restate ayrı bir selector hook'u ya da türetilmiş atom yerine aynı hook çağrısını kullanır.

Taslak kaydetme

Başlangıçta kayıtlı taslağı geri yükleyin, tıklayınca kaydedin ve kaydediliyor, kaydedilmedi ve başarısız durumlarını gösterin.

Redux Toolkit Güncellemeleri, React context ile sağlanan bir store'a gönderilen slice ve action'lar olarak düzenler. Mükemmel DevTools ve büyük ekipler için katı, öngörülebilir bir güncelleme akışı.

Zustand create() ile bir store hook'u oluşturur ve setState ile değiştirir. Minik ve esnek; kalıcılık ve DevTools için middleware'leri var.

Jotai Atom'ları ve türetilmiş atom'ları birleştirir, isteğe bağlı olarak bir Provider içinde. Birçok küçük durum parçası arasında ince taneli bağımlılıklar.

Redux Toolkit84 satır · 4 API
JavaScript / JSX
import { useEffect, useState } from 'react';
import { configureStore, createSlice } from '@reduxjs/toolkit';
import { Provider, useSelector } from 'react-redux';

function openDraftDB() {
  return new Promise((resolve, reject) => {
    const request = indexedDB.open('draft-example', 1);
    let blocked = false;
    request.onupgradeneeded = () => {
      request.result.createObjectStore('drafts');
    };
    request.onblocked = () => {
      blocked = true;
      reject(new Error('Close other tabs to upgrade storage'));
    };
    request.onerror = () => reject(request.error);
    request.onsuccess = () => {
      const db = request.result;
      if (blocked) {
        db.close();
        return;
      }
      db.onversionchange = () => db.close();
      resolve(db);
    };
  });
}

async function storedDraft(mode, text) {
  const db = await openDraftDB();
  try {
    return await new Promise((resolve, reject) => {
      const tx = db.transaction('drafts', mode);
      const store = tx.objectStore('drafts');
      const request = mode === 'readonly' ? store.get('draft') : store.put(text, 'draft');
      tx.oncomplete = () => resolve(request.result);
      tx.onabort = () => reject(tx.error || new Error('Storage aborted'));
    });
  } finally {
    db.close();
  }
}

const draft = createSlice({
  name: 'draft',
  initialState: '',
  reducers: { edit: (_, action) => action.payload },
});
const store = configureStore({ reducer: { draft: draft.reducer } });
const hydrated = storedDraft('readonly').then((saved) => {
  if (saved === undefined) return;
  if (typeof saved !== 'string') throw new Error('Invalid draft');
  const value = saved;
  store.dispatch(draft.actions.edit(value));
});
// Observe errors immediately, even before the component mounts.
hydrated.catch(() => {});

function DraftEditor() {
  const text = useSelector((state) => state.draft);
  const [ready, setReady] = useState(false);
  const [saving, setSaving] = useState(false);
  const [message, setMessage] = useState('Loading');
  useEffect(() => {
    let active = true;
    hydrated.then(
      () => {
        if (active) {
          setReady(true);
          setMessage('Ready');
        }
      },
      () => {
        if (active) setMessage('Storage error');
      },
    );
    return () => {
      active = false;
    };
  }, []);
  async function save() {
    setSaving(true);
    try {
      await storedDraft('readwrite', store.getState().draft);
      setMessage('Saved');
    } catch {
      setMessage('Save failed');
    } finally {
      setSaving(false);
    }
  }
  return (
    <>
      <label>
        Draft
        <textarea
          value={text}
          disabled={!ready || saving}
          onChange={(event) => {
            const value = event.target.value;
            store.dispatch(draft.actions.edit(value));
            setMessage('Edited');
          }}
        />
      </label>
      <output>{text}</output>
      <button disabled={!ready || saving} onClick={save}>
        Save
      </button>
      <p>{message}</p>
    </>
  );
}

export default function App() {
  return (
    <Provider store={store}>
      <DraftEditor />
    </Provider>
  );
}
Zustand79 satır · 1 API
JavaScript / JSX
import { useEffect, useState } from 'react';
import { create } from 'zustand';

function openDraftDB() {
  return new Promise((resolve, reject) => {
    const request = indexedDB.open('draft-example', 1);
    let blocked = false;
    request.onupgradeneeded = () => {
      request.result.createObjectStore('drafts');
    };
    request.onblocked = () => {
      blocked = true;
      reject(new Error('Close other tabs to upgrade storage'));
    };
    request.onerror = () => reject(request.error);
    request.onsuccess = () => {
      const db = request.result;
      if (blocked) {
        db.close();
        return;
      }
      db.onversionchange = () => db.close();
      resolve(db);
    };
  });
}

async function storedDraft(mode, text) {
  const db = await openDraftDB();
  try {
    return await new Promise((resolve, reject) => {
      const tx = db.transaction('drafts', mode);
      const store = tx.objectStore('drafts');
      const request = mode === 'readonly' ? store.get('draft') : store.put(text, 'draft');
      tx.oncomplete = () => resolve(request.result);
      tx.onabort = () => reject(tx.error || new Error('Storage aborted'));
    });
  } finally {
    db.close();
  }
}

const useDraft = create(() => ({ text: '' }));
const hydrated = storedDraft('readonly').then((saved) => {
  if (saved === undefined) return;
  if (typeof saved !== 'string') throw new Error('Invalid draft');
  const value = saved;
  useDraft.setState({ text: value });
});
// Observe errors immediately, even before the component mounts.
hydrated.catch(() => {});

function DraftEditor() {
  const text = useDraft((state) => state.text);
  const [ready, setReady] = useState(false);
  const [saving, setSaving] = useState(false);
  const [message, setMessage] = useState('Loading');
  useEffect(() => {
    let active = true;
    hydrated.then(
      () => {
        if (active) {
          setReady(true);
          setMessage('Ready');
        }
      },
      () => {
        if (active) setMessage('Storage error');
      },
    );
    return () => {
      active = false;
    };
  }, []);
  async function save() {
    setSaving(true);
    try {
      await storedDraft('readwrite', useDraft.getState().text);
      setMessage('Saved');
    } catch {
      setMessage('Save failed');
    } finally {
      setSaving(false);
    }
  }
  return (
    <>
      <label>
        Draft
        <textarea
          value={text}
          disabled={!ready || saving}
          onChange={(event) => {
            const value = event.target.value;
            useDraft.setState({ text: value });
            setMessage('Edited');
          }}
        />
      </label>
      <output>{text}</output>
      <button disabled={!ready || saving} onClick={save}>
        Save
      </button>
      <p>{message}</p>
    </>
  );
}

export default function App() {
  return <DraftEditor />;
}
Jotai80 satır · 3 API
JavaScript / JSX
import { useEffect, useState } from 'react';
import { atom, createStore, useAtomValue } from 'jotai';

function openDraftDB() {
  return new Promise((resolve, reject) => {
    const request = indexedDB.open('draft-example', 1);
    let blocked = false;
    request.onupgradeneeded = () => {
      request.result.createObjectStore('drafts');
    };
    request.onblocked = () => {
      blocked = true;
      reject(new Error('Close other tabs to upgrade storage'));
    };
    request.onerror = () => reject(request.error);
    request.onsuccess = () => {
      const db = request.result;
      if (blocked) {
        db.close();
        return;
      }
      db.onversionchange = () => db.close();
      resolve(db);
    };
  });
}

async function storedDraft(mode, text) {
  const db = await openDraftDB();
  try {
    return await new Promise((resolve, reject) => {
      const tx = db.transaction('drafts', mode);
      const store = tx.objectStore('drafts');
      const request = mode === 'readonly' ? store.get('draft') : store.put(text, 'draft');
      tx.oncomplete = () => resolve(request.result);
      tx.onabort = () => reject(tx.error || new Error('Storage aborted'));
    });
  } finally {
    db.close();
  }
}

const draftAtom = atom('');
const store = createStore();
const hydrated = storedDraft('readonly').then((saved) => {
  if (saved === undefined) return;
  if (typeof saved !== 'string') throw new Error('Invalid draft');
  const value = saved;
  store.set(draftAtom, value);
});
// Observe errors immediately, even before the component mounts.
hydrated.catch(() => {});

function DraftEditor() {
  const text = useAtomValue(draftAtom, { store });
  const [ready, setReady] = useState(false);
  const [saving, setSaving] = useState(false);
  const [message, setMessage] = useState('Loading');
  useEffect(() => {
    let active = true;
    hydrated.then(
      () => {
        if (active) {
          setReady(true);
          setMessage('Ready');
        }
      },
      () => {
        if (active) setMessage('Storage error');
      },
    );
    return () => {
      active = false;
    };
  }, []);
  async function save() {
    setSaving(true);
    try {
      await storedDraft('readwrite', store.get(draftAtom));
      setMessage('Saved');
    } catch {
      setMessage('Save failed');
    } finally {
      setSaving(false);
    }
  }
  return (
    <>
      <label>
        Draft
        <textarea
          value={text}
          disabled={!ready || saving}
          onChange={(event) => {
            const value = event.target.value;
            store.set(draftAtom, value);
            setMessage('Edited');
          }}
        />
      </label>
      <output>{text}</output>
      <button disabled={!ready || saving} onClick={save}>
        Save
      </button>
      <p>{message}</p>
    </>
  );
}

export default function App() {
  return <DraftEditor />;
}

restate persistedRestate otomatik olarak geri yükler; useStatus kaydetmeyi, kaydedilmemiş değişiklikleri ve hataları bildirir.

restate18 satır · 1 API
JavaScript / JSX
import { persistedRestate } from '@kkwaenggwari/restate';

const useDraft = persistedRestate('', {
  key: 'draft',
  validate: (value) => typeof value === 'string',
});

export default function App() {
  const text = useDraft();
  const { dirty, operation, error } = useDraft.useStatus();
  const saving = operation === 'save';
  const message = error ? 'Save failed' : saving ? 'Saving…' : dirty ? 'Edited' : 'Saved';

  return (
    <>
      <label>
        Draft
        <textarea value={text} onChange={(event) => useDraft.set(event.target.value)} />
      </label>
      <output>{text}</output>
      <button disabled={saving} onClick={() => useDraft.save().catch(() => {})}>
        Save
      </button>
      <p>{message}</p>
    </>
  );
}

Diğer sürümler aynı IndexedDB kodunu elle yazar. Kalıcılık middleware'leri ya da depolama araçları bir adaptörle bunu kısaltabilir; o kod burada sayılmaz.

Belge başına durum

İki belge bağımsız durum tutar ve birini kapatmak onu serbest bırakır.

Redux Toolkit Güncellemeleri, React context ile sağlanan bir store'a gönderilen slice ve action'lar olarak düzenler. Mükemmel DevTools ve büyük ekipler için katı, öngörülebilir bir güncelleme akışı.

Zustand create() ile bir store hook'u oluşturur ve setState ile değiştirir. Minik ve esnek; kalıcılık ve DevTools için middleware'leri var.

Jotai Atom'ları ve türetilmiş atom'ları birleştirir, isteğe bağlı olarak bir Provider içinde. Birçok küçük durum parçası arasında ince taneli bağımlılıklar.

Redux Toolkit42 satır · 4 API
JavaScript / JSX
import { useState } from 'react';
import { configureStore, createSlice } from '@reduxjs/toolkit';
import { Provider, useSelector } from 'react-redux';

const draft = createSlice({
  name: 'draft',
  initialState: '',
  reducers: { edit: (_, action) => action.payload },
});
const selectionSlice = createSlice({
  name: 'selection',
  initialState: 0,
  reducers: { next: (index) => index + 1 },
});
function createDocument() {
  return {
    store: configureStore({
      reducer: {
        draft: draft.reducer,
        selection: selectionSlice.reducer,
      },
    }),
  };
}

function Document({ doc, name }) {
  const text = useSelector((state) => state.draft);
  const selection = useSelector((state) => state.selection);
  return (
    <section>
      <label>
        {name}
        <input
          value={text}
          onChange={(event) => doc.store.dispatch(draft.actions.edit(event.target.value))}
        />
      </label>
      <output>{text}</output>
      <button onClick={() => doc.store.dispatch(selectionSlice.actions.next())}>
        Selection: {selection}
      </button>
    </section>
  );
}

function DocumentSlot({ name }) {
  const [doc] = useState(createDocument);
  return (
    <Provider store={doc.store}>
      <Document doc={doc} name={name} />
    </Provider>
  );
}

export default function App() {
  const [leftOpen, setLeftOpen] = useState(true);
  return (
    <>
      <button onClick={() => setLeftOpen((open) => !open)}>
        {leftOpen ? 'Close left' : 'Open left'}
      </button>
      {leftOpen && <DocumentSlot name="Left" />}
      <DocumentSlot name="Right" />
    </>
  );
}
Zustand35 satır · 2 API
JavaScript / JSX
import { useState } from 'react';
import { useStore } from 'zustand';
import { createStore } from 'zustand/vanilla';

function createDocument() {
  return {
    draft: createStore(() => ({ text: '' })),
    selection: createStore(() => ({ index: 0 })),
  };
}

function Document({ doc, name }) {
  const text = useStore(doc.draft, (state) => state.text);
  const selection = useStore(doc.selection, (state) => state.index);
  return (
    <section>
      <label>
        {name}
        <input
          value={text}
          onChange={(event) => doc.draft.setState({ text: event.target.value })}
        />
      </label>
      <output>{text}</output>
      <button onClick={() => doc.selection.setState((s) => ({ index: s.index + 1 }))}>
        Selection: {selection}
      </button>
    </section>
  );
}

function DocumentSlot({ name }) {
  const [doc] = useState(createDocument);
  return <Document doc={doc} name={name} />;
}

export default function App() {
  const [leftOpen, setLeftOpen] = useState(true);
  return (
    <>
      <button onClick={() => setLeftOpen((open) => !open)}>
        {leftOpen ? 'Close left' : 'Open left'}
      </button>
      {leftOpen && <DocumentSlot name="Left" />}
      <DocumentSlot name="Right" />
    </>
  );
}
Jotai33 satır · 3 API
JavaScript / JSX
import { useState } from 'react';
import { atom, createStore, useAtomValue } from 'jotai';

const draftAtom = atom('');
const selectionAtom = atom(0);
function createDocument() {
  return { store: createStore() };
}

function Document({ doc, name }) {
  const text = useAtomValue(draftAtom, { store: doc.store });
  const selection = useAtomValue(selectionAtom, { store: doc.store });
  return (
    <section>
      <label>
        {name}
        <input value={text} onChange={(event) => doc.store.set(draftAtom, event.target.value)} />
      </label>
      <output>{text}</output>
      <button onClick={() => doc.store.set(selectionAtom, (n) => n + 1)}>
        Selection: {selection}
      </button>
    </section>
  );
}

function DocumentSlot({ name }) {
  const [doc] = useState(createDocument);
  return <Document doc={doc} name={name} />;
}

export default function App() {
  const [leftOpen, setLeftOpen] = useState(true);
  return (
    <>
      <button onClick={() => setLeftOpen((open) => !open)}>
        {leftOpen ? 'Close left' : 'Open left'}
      </button>
      {leftOpen && <DocumentSlot name="Left" />}
      <DocumentSlot name="Right" />
    </>
  );
}

restate useRestateScope store'ları oluşturur ve ayrılmadan sonra yok eder.

restate27 satır · 2 API
JavaScript / JSX
import { useState } from 'react';
import { restate, useRestateScope } from '@kkwaenggwari/restate';

function Document({ name }) {
  const doc = useRestateScope((scope) => ({
    useDraft: restate('', { scope }),
    useSelection: restate(0, { scope }),
  }));
  const text = doc.useDraft();
  const selection = doc.useSelection();
  return (
    <section>
      <label>
        {name}
        <input value={text} onChange={(event) => doc.useDraft.set(event.target.value)} />
      </label>
      <output>{text}</output>
      <button onClick={() => doc.useSelection.set((n) => n + 1)}>Selection: {selection}</button>
    </section>
  );
}

export default function App() {
  const [leftOpen, setLeftOpen] = useState(true);
  return (
    <>
      <button onClick={() => setLeftOpen((open) => !open)}>
        {leftOpen ? 'Close left' : 'Open left'}
      </button>
      {leftOpen && <Document name="Left" />}
      <Document name="Right" />
    </>
  );
}

Jotai'de bir Provider ya da store, Zustand'da vanilla store'lar da durumu ayırabilir; bunları siz oluşturup bağlarsınız.

Bu sayılar nasıl hesaplanır

Gösterilen kodun boş olmayan satırları ve her durum kütüphanesinden import edilen adlar (React import'ları sayılmaz). Her sürüm aynı UI'yi aynı depolama, aynı yükleme ve hata durumlarıyla render eder. restate örnekleri, uygulama giriş noktasında await restateManager.ready olduğunu varsayar. Kaynaklar her projenin resmi belgeleriyle doğrulandı:

  • Redux Toolkit — Redux Toolkit · Quick Start, React Redux · useSelector, Redux Toolkit · configureStore. Denetlenebilir tek bir action günlüğü ve büyük bir middleware ekosistemi en önemli şey olduğunda bunu seçin
  • Zustand — Zustand · Introduction, Zustand · persist. En küçük çekirdeği istediğinizde ve middleware birleştirmeyi tercih ettiğinizde bunu seçin
  • Jotai — Jotai · atom, Jotai · Storage, Jotai · Provider. Durumunuz doğası gereği küçük türetilmiş değerlerden oluşan bir grafikse bunu seçin

02 — Hızlı

Yalnızca değişeni render edin. Bir kez yazın.

İki panel de tarayıcınızda gerçek restate paketini çalıştırır. Tıklayın, yazın ve sayaçları izleyin.

Render haritası

Aynı dört alan, iki şekilde okunuyor. Bir alanı değiştirin ve render'ları sayın.

Tüm store'u okur
  • Ad
  • Tema
  • Sayaç
  • Taslak
Tek alanı seçer
  • Ad
  • Tema
  • Sayaç
  • Taslak

Birleştirilmiş yazmalar

autoSave yazmada bir duraklamayı bekler, sonra bir kez yazar. Art arda gelen save() çağrıları kuyruktaki tek bir yazmayı paylaşır.

persistedRestate('', { key: 'note', autoSave: { delayMs: 400 } });

Sayılar bu sayfadaki gerçek React render'larından ve yazmaları sayan bir depolama adaptöründen gelir. Diğer kütüphaneler de değer seçebilir; burada seçmek yalnızca bir okuma biçimidir.

03 — Kararlı

Depolama başarısız olduğunda verileriniz yerinde kalır.

Durum tam da kaydederken kaybolur: yavaş diskler, engellenmiş depolama, kapanan sekmeler. Bunlar restate 1.0'ın garantileridir, tavsiye değil.

Hata laboratuvarını açın Güvenilirlik kılavuzunu okuyun
  1. 01

    Kaydetmeler sırayla çalışır

    Her store depolama işlemlerini birer birer yürütür; yavaş bir kaydetme hiçbir zaman eski bir değerin yenisinin üzerine yazmasına yol açmaz.

    save() · restore()
  2. 02

    Bekleyen kaydetme en son değeri alır

    Başka bir kaydetme kuyruktayken save() çağırmak, fazladan yazma biriktirmek yerine ona katılır.

    save(): Promise<T>
  3. 03

    Okunmamış kayıtlar asla yanlışlıkla değiştirilmez

    Bir kayıt yüklenemezse autoSave ve toplu kaydetmeler ona dokunmaz ve LOAD_FAILED bildirir. Onu yalnızca açık bir save() değiştirebilir.

    LOAD_FAILED
  4. 04

    Ayrıldıktan sonra da kaydetme tamamlanır

    Ayrılmadan önce istenen kaydetmeler tamamlanır. Yok edilmiş bir store'a sonradan yapılan yazmalar, ayrılmadan sonraki React durumu gibi yok sayılır.

    useRestateScope
  5. 05

    Depolama yok mu? Uygulama yine açılır

    Sunucu tarafı render sırasında ya da depolama engellendiğinde store'lar bellekte çalışmayı sürdürür ve depolamanın kullanılamadığını bildirir.

    status().available
  6. 06

    Hatalar neyi ve nerede olduğunu söyler

    Her restate hatası tipli bir kod ve kaydının key'ini taşır; böylece doğru mesajı gösterebilirsiniz.

    error.code · error.key

Uygulamanızla birlikte büyür

Bildirimi değiştirin. Bileşenler aynı kalsın.

Kaydetme, otomatik kaydetme ve doğrulama aynı store'un seçenekleridir. Sağdaki bileşen hiç değişmez.

  1. Bellek

    Bellekte paylaşılan bir değer.

    import { restate } from '@kkwaenggwari/restate';
    
    export const useDraft = restate('');
  2. Kayıtlı

    Otomatik geri yüklenir; save() çağırdığınızda yazılır.

    import { persistedRestate } from '@kkwaenggwari/restate';
    
    export const useDraft = persistedRestate('', { key: 'draft' });
  3. Otomatik kaydetme

    Yazmada 500 ms duraklamadan sonra bir kez yazılır.

    import { persistedRestate } from '@kkwaenggwari/restate';
    
    export const useDraft = persistedRestate('', {
      key: 'draft',
      autoSave: { delayMs: 500 },
    });
  4. Doğrulamalı

    Eski kayıtlar kullanılmadan önce taşınır ve doğrulanır.

    import { persistedRestate } from '@kkwaenggwari/restate';
    
    export const useDraft = persistedRestate('', {
      key: 'draft',
      autoSave: { delayMs: 500 },
      version: 2,
      migrate: (value) => String(value ?? ''),
      validate: (value) => typeof value === 'string',
    });

Bileşen — her adımda aynı

function Editor() {
  const text = useDraft();

  return <textarea value={text} onChange={(event) => useDraft.set(event.target.value)} />;
}

React'in çalıştığı her yerde çalışır

Her React ortamı için tek paket.

  • react >=16.8.0

    React

    React 16.8 ve sonrasıyla, tarayıcıda ve sunucu tarafı render sırasında çalışır.

  • react-native-mmkv >=2.0.0

    React Native

    Aynı import'lar. react-native-mmkv'yi kurduğunuz anda kaydetme MMKV'yi kullanır.

  • SSR

    Sunucu tarafı render

    Bileşen store'ları sunucu anlık görüntüsünü props'tan alır ve hidrasyondan sonra yüklemeye başlar.

  • index.d.ts

    TypeScript

    Bildirimler pakete dahildir. Selector'lar, durum alanları ve hata kodları tiplidir.

Başlarken

Bir dakikada ilk paylaşılan durumunuz.

Kurun, bildirin, kullanın. Uygulamanız ihtiyaç duyduğunda kaydetmeyi ekleyin.

  1. 01
    Kurulum
    Terminal
    npm install @kkwaenggwari/restate
  2. 02
    Bir store bildirin
    JavaScript / JSX
    export const useCart = restate({ items: 0, total: 0 });
  3. 03
    Herhangi bir bileşende okuyun
    JavaScript / JSX
    const items = useCart((cart) => cart.items);

KKWAENGGWARI

Projeler

Belgelerde ara

Tüm kılavuzların başlık, açıklama ve içeriğinde arayın.