React और React Native के लिए स्टेट · 1.0
स्टेट साझा करें।एक हुक।बस।
एक पंक्ति में स्टोर घोषित करें और किसी भी कंपोनेंट में इस्तेमाल करें, बिना Provider, action और reducer के। कंपोनेंट तभी दोबारा रेंडर होता है जब उसका चुना हुआ मान बदले, और सहेजना तब होता है जब आप तय करें।
npm install @kkwaenggwari/restateलाइव — असली restate स्टोर
useCart.set(cart => ({ ...cart, items: cart.items + 1, total: cart.total + 12 }))items और total बदलते हैं: तीन कार्ड रेंडर होते हैं, गिफ़्ट कार्ड स्थिर रहता है।
- आसान0सेटअप के लिए Provider, action और reducerमान घोषित करें और इस्तेमाल करें। पहले से कुछ भी जोड़ना नहीं पड़ता।
- तेज़11 → 1ग्यारह बदलाव, एक लेखनautoSave ठहराव का इंतज़ार करता है, इसलिए ग्यारह तेज़ बदलाव एक लेखन बन जाते हैं।
- स्थिर26टाइप्ड त्रुटि कोडहर त्रुटि बताती है कि क्या गड़बड़ हुई और किस रिकॉर्ड से जुड़ी है।
01 — आसान
वही सुविधा, कम अवधारणाएँ।
एक ही काम के चार कार्यान्वयन साथ-साथ। आँकड़े यहाँ दिखाए गए कोड से आते हैं और इस साइट के बिल्ड के समय मापे जाते हैं।
साझा काउंटर
दो कंपोनेंट एक ही संख्या पढ़ते और अपडेट करते हैं।
Redux Toolkit अपडेट को slice और action में व्यवस्थित करता है, जो React context से मिलने वाले स्टोर को भेजे जाते हैं। बेहतरीन DevTools और बड़ी टीमों के लिए सख़्त, अनुमानित अपडेट प्रवाह।
Zustand create() से स्टोर हुक बनाता है और setState से उसे बदलता है। बहुत छोटा और लचीला, persistence और DevTools के middleware के साथ।
Jotai atom और व्युत्पन्न atom को जोड़ता है, चाहें तो Provider के भीतर। स्टेट के कई छोटे टुकड़ों के बीच बारीक निर्भरताएँ।
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 एक घोषणा ही स्टोर भी है और हुक भी।
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 />
</>
);
}इस काम के लिए Zustand और Jotai भी छोटे हैं और Provider के बिना चलते हैं। अंतर तब बढ़ता है जब सहेजना और हर दस्तावेज़ का स्टेट जुड़ता है।
फ़ील्ड चुनना
सिर्फ़ टेक्स्ट बदलने पर शीर्षक कंपोनेंट रेंडर नहीं होना चाहिए।
Redux Toolkit अपडेट को slice और action में व्यवस्थित करता है, जो React context से मिलने वाले स्टोर को भेजे जाते हैं। बेहतरीन DevTools और बड़ी टीमों के लिए सख़्त, अनुमानित अपडेट प्रवाह।
Zustand create() से स्टोर हुक बनाता है और setState से उसे बदलता है। बहुत छोटा और लचीला, persistence और DevTools के middleware के साथ।
Jotai atom और व्युत्पन्न atom को जोड़ता है, चाहें तो Provider के भीतर। स्टेट के कई छोटे टुकड़ों के बीच बारीक निर्भरताएँ।
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 जिस हुक को आप पहले से इस्तेमाल करते हैं, उसी को selector दें।
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>
</>
);
}यहाँ के सभी टूल चुन सकते हैं। restate अलग selector हुक या व्युत्पन्न atom की जगह वही हुक कॉल इस्तेमाल करता है।
ड्राफ़्ट सहेजना
स्टार्टअप पर सहेजा गया ड्राफ़्ट वापस लाएँ, क्लिक पर सहेजें, और सहेजा जा रहा, बिना सहेजा और विफल स्थितियाँ दिखाएँ।
Redux Toolkit अपडेट को slice और action में व्यवस्थित करता है, जो React context से मिलने वाले स्टोर को भेजे जाते हैं। बेहतरीन DevTools और बड़ी टीमों के लिए सख़्त, अनुमानित अपडेट प्रवाह।
Zustand create() से स्टोर हुक बनाता है और setState से उसे बदलता है। बहुत छोटा और लचीला, persistence और DevTools के middleware के साथ।
Jotai atom और व्युत्पन्न atom को जोड़ता है, चाहें तो Provider के भीतर। स्टेट के कई छोटे टुकड़ों के बीच बारीक निर्भरताएँ।
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 अपने-आप वापस लाता है, और useStatus सहेजना, बिना सहेजे बदलाव और त्रुटियाँ बताता है।
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>
</>
);
}दूसरे संस्करण यही IndexedDB कोड हाथ से लिखते हैं। उनका persistence middleware या स्टोरेज टूल एडेप्टर के साथ इसे छोटा कर सकता है; वह कोड यहाँ नहीं गिना जाता।
हर दस्तावेज़ का स्टेट
दो दस्तावेज़ अलग-अलग स्टेट रखते हैं, और एक को बंद करने पर उसका स्टेट छूट जाता है।
Redux Toolkit अपडेट को slice और action में व्यवस्थित करता है, जो React context से मिलने वाले स्टोर को भेजे जाते हैं। बेहतरीन DevTools और बड़ी टीमों के लिए सख़्त, अनुमानित अपडेट प्रवाह।
Zustand create() से स्टोर हुक बनाता है और setState से उसे बदलता है। बहुत छोटा और लचीला, persistence और DevTools के middleware के साथ।
Jotai atom और व्युत्पन्न atom को जोड़ता है, चाहें तो Provider के भीतर। स्टेट के कई छोटे टुकड़ों के बीच बारीक निर्भरताएँ।
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 स्टोर बनाता है और अनमाउंट के बाद उन्हें नष्ट करता है।
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 में Provider या स्टोर और Zustand में vanilla स्टोर भी स्टेट अलग कर सकते हैं; आप उन्हें ख़ुद बनाते और जोड़ते हैं।
ये आँकड़े कैसे गिने जाते हैं
दिखाए गए कोड की ख़ाली न होने वाली पंक्तियाँ और हर स्टेट लाइब्रेरी से इम्पोर्ट किए गए नाम (React इम्पोर्ट नहीं गिने जाते)। हर संस्करण वही UI, वही स्टोरेज और वही लोडिंग व त्रुटि स्थितियाँ रेंडर करता है। restate के उदाहरण ऐप के एंट्री पॉइंट में await restateManager.ready मानते हैं। स्रोत हर प्रोजेक्ट के आधिकारिक दस्तावेज़ों से जाँचे गए हैं:
- Redux Toolkit — Redux Toolkit · Quick Start, React Redux · useSelector, Redux Toolkit · configureStore. इसे तब चुनें जब एक जाँचने योग्य action लॉग और बड़ा middleware इकोसिस्टम सबसे ज़रूरी हो
- Zustand — Zustand · Introduction, Zustand · persist. इसे तब चुनें जब आपको सबसे छोटा कोर चाहिए और middleware जोड़ना पसंद हो
- Jotai — Jotai · atom, Jotai · Storage, Jotai · Provider. इसे तब चुनें जब आपका स्टेट स्वाभाविक रूप से छोटे व्युत्पन्न मानों का ग्राफ़ हो
02 — तेज़
सिर्फ़ बदला हुआ रेंडर करें। एक बार लिखें।
दोनों पैनल आपके ब्राउज़र में असली restate पैकेज चलाते हैं। क्लिक करें, टाइप करें और काउंटर देखें।
रेंडर मैप
वही चार फ़ील्ड, दो तरह से पढ़े गए। कोई फ़ील्ड बदलें और रेंडर गिनें।
- नाम
- थीम
- काउंटर
- ड्राफ़्ट
- नाम
- थीम
- काउंटर
- ड्राफ़्ट
एक साथ लिखे गए बदलाव
autoSave टाइपिंग में ठहराव का इंतज़ार करता है और फिर एक बार लिखता है। save() की लगातार कॉल कतार में एक ही लेखन साझा करती हैं।
persistedRestate('', { key: 'note', autoSave: { delayMs: 400 } });आँकड़े इस पेज पर असली React रेंडर और लेखन गिनने वाले स्टोरेज एडेप्टर से आते हैं। दूसरी लाइब्रेरी भी मान चुन सकती हैं; यहाँ चुनना बस पढ़ने का तरीक़ा है।
03 — स्थिर
स्टोरेज विफल हो, तब भी आपका डेटा सुरक्षित रहता है।
स्टेट ठीक सहेजते समय खोता है: धीमी डिस्क, अवरुद्ध स्टोरेज, बंद टैब। ये restate 1.0 की गारंटी हैं, सलाह नहीं।
- 01
सहेजना क्रम से होता है
हर स्टोर स्टोरेज के काम एक-एक करके चलाता है, इसलिए धीमा सहेजना कभी भी पुराने मान को नए पर लिखने नहीं देता।
save() · restore() - 02
लंबित सहेजना नवीनतम मान लेता है
जब दूसरा सहेजना कतार में हो तब save() कॉल करने पर वह उसी में जुड़ जाता है, अतिरिक्त लेखन जमा नहीं करता।
save(): Promise<T> - 03
बिना पढ़े रिकॉर्ड कभी ग़लती से नहीं बदले जाते
अगर कोई रिकॉर्ड लोड नहीं हुआ, तो autoSave और सामूहिक सहेजना उसे नहीं छूते और LOAD_FAILED बताते हैं। सिर्फ़ स्पष्ट save() उसे बदल सकता है।
LOAD_FAILED - 04
अनमाउंट के बाद भी सहेजना पूरा होता है
अनमाउंट से पहले माँगा गया सहेजना पूरा होता है। नष्ट हुए स्टोर में बाद के लेखन अनदेखे होते हैं, जैसे अनमाउंट के बाद React का स्टेट।
useRestateScope - 05
स्टोरेज नहीं? ऐप फिर भी शुरू होता है
सर्वर रेंडरिंग के दौरान या स्टोरेज अवरुद्ध होने पर स्टोर मेमोरी में चलते रहते हैं और बताते हैं कि स्टोरेज उपलब्ध नहीं है।
status().available - 06
त्रुटियाँ बताती हैं क्या और कहाँ
हर restate त्रुटि में टाइप्ड कोड और उसके रिकॉर्ड की key होती है, ताकि आप सही संदेश दिखा सकें।
error.code · error.key
आपके ऐप के साथ बढ़ता है
घोषणा बदलें। कंपोनेंट वैसे ही रखें।
सहेजना, अपने-आप सहेजना और सत्यापन एक ही स्टोर के विकल्प हैं। दाईं ओर का कंपोनेंट कभी नहीं बदलता।
मेमोरी
मेमोरी में साझा मान।
import { restate } from '@kkwaenggwari/restate'; export const useDraft = restate('');सहेजा हुआ
अपने-आप वापस आता है; save() कॉल करने पर लिखा जाता है।
import { persistedRestate } from '@kkwaenggwari/restate'; export const useDraft = persistedRestate('', { key: 'draft' });अपने-आप सहेजना
टाइपिंग में 500 ms के ठहराव के बाद एक बार लिखा जाता है।
import { persistedRestate } from '@kkwaenggwari/restate'; export const useDraft = persistedRestate('', { key: 'draft', autoSave: { delayMs: 500 }, });सत्यापन के साथ
पुराने रिकॉर्ड इस्तेमाल से पहले माइग्रेट और सत्यापित होते हैं।
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', });
कंपोनेंट — हर चरण में वही
function Editor() {
const text = useDraft();
return <textarea value={text} onChange={(event) => useDraft.set(event.target.value)} />;
}जहाँ React चलता है, वहाँ चलता है
हर React वातावरण के लिए एक पैकेज।
react >=16.8.0React
React 16.8 और नए संस्करणों के साथ, ब्राउज़र में और सर्वर रेंडरिंग के दौरान काम करता है।
react-native-mmkv >=2.0.0React Native
वही इम्पोर्ट। react-native-mmkv इंस्टॉल करते ही सहेजना MMKV इस्तेमाल करता है।
SSRसर्वर रेंडरिंग
कंपोनेंट के स्टोर props से सर्वर स्नैपशॉट लेते हैं और हाइड्रेशन के बाद लोड करना शुरू करते हैं।
index.d.tsTypeScript
डिक्लेरेशन साथ आते हैं। सेलेक्टर, स्टेटस फ़ील्ड और त्रुटि कोड टाइप्ड हैं।
शुरुआत
एक मिनट में आपका पहला साझा स्टेट।
इंस्टॉल करें, घोषित करें, इस्तेमाल करें। सहेजना तब जोड़ें जब ऐप को उसकी ज़रूरत हो।
- 01इंस्टॉल करें
npm install @kkwaenggwari/restate - 02स्टोर घोषित करें
export const useCart = restate({ items: 0, total: 0 }); - 03किसी भी कंपोनेंट में पढ़ें
const items = useCart((cart) => cart.items);
KKWAENGGWARI