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.
npm install @kkwaenggwari/restateCanlı — 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.
- Basit0Kurulum için Provider, action ve reducerBir değer bildirin ve kullanın. Önceden bağlanacak hiçbir şey yok.
- Hızlı11 → 1On bir değişiklik, tek yazmaautoSave bir duraklamayı bekler; on bir hızlı değişiklik tek bir yazmaya dönüşür.
- Kararlı26Tipli hata kodlarıHer hata neyin yanlış gittiğini ve hangi kaydı ilgilendirdiğini söyler.
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.
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>
);
}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 />
</>
);
}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.
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.
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>
);
}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>
</>
);
}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.
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.
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>
);
}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 />;
}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.
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.
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" />
</>
);
}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" />
</>
);
}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.
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.
- Ad
- Tema
- Sayaç
- Taslak
- 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.
- 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() - 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> - 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 - 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 - 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 - 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.
Bellek
Bellekte paylaşılan bir değer.
import { restate } from '@kkwaenggwari/restate'; export const useDraft = restate('');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' });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 }, });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.0React
React 16.8 ve sonrasıyla, tarayıcıda ve sunucu tarafı render sırasında çalışır.
react-native-mmkv >=2.0.0React Native
Aynı import'lar. react-native-mmkv'yi kurduğunuz anda kaydetme MMKV'yi kullanır.
SSRSunucu 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.tsTypeScript
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.
- 01Kurulum
npm install @kkwaenggwari/restate - 02Bir store bildirin
export const useCart = restate({ items: 0, total: 0 }); - 03Herhangi bir bileşende okuyun
const items = useCart((cart) => cart.items);
KKWAENGGWARI