Provide the store
To provide the store you just created to all your app,
import the StoreProvider component from kiss-for-react and wrap your app with it.
Note your code should have a single store provider, at the top of your component tree.
Then, pass the store as a prop to the StoreProvider.
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
const rootElement = document.getElementById("root")!;
const root = ReactDOM.createRoot(rootElement);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
import React from "react";
import { createStore, StoreProvider } from "kiss-for-react";
import State from "./State";
const store = createStore<State>({ initialState: ... });
function App() {
return (
<StoreProvider store={store}>
<AppContent />
</StoreProvider>
);
};
Create the store outside the components, as above, so that it lives for the whole app. If the
store prop changes, the components below switch to the new store: they stop listening to the
old one, read the new one right away, and the useStoreEffect callbacks run onUnmount for the
old store and onMount for the new one.
Server-side rendering
Kiss works with renderToString and hydrateRoot. Create one store per request, so that
requests don't share state.
On the server, the HTML shows the initialState the store was created with. If you dispatch
actions before rendering, wait for them to finish, and pass the state to render as
serverState:
const store = createStore<State>({ initialState: new State(), server: true });
await store.dispatchAndWait(new LoadData());
const html = renderToString(
<StoreProvider store={store} serverState={store.state}>
<App />
</StoreProvider>
);
const transfer = serialize(store.state); // Put it in the HTML, for the client.
On the client, create the store with the state transferred from the server, and hydrate. React
needs to render exactly what the HTML shows, so if the client store may have changed before
hydrating (for example, a persistor restored a newer state), pass the transferred state as
serverState. After hydration, the components catch up with the live state:
const store = createStore<State>({ initialState: deserialize(transfer) });
hydrateRoot(
document.getElementById('root')!,
<StoreProvider store={store} serverState={store.state}>
<App />
</StoreProvider>
);
Rebuild the same state on the client that the server rendered: for a plain object, JSON is
enough; for class instances, Maps and Sets, use your own toJSON/fromJSON code, or the
serializer you use for persistence.
On the server and while hydrating, useIsWaiting and useIsFailed are false,
useExceptionFor is null, useSuspense never suspends or throws, and useIsStoreReady is
true: the HTML never shows an action in progress, a failed action, or a store that is not
ready. After hydration, these hooks follow the live store. So, on the server, wait for your
actions to finish before rendering.
The server store is created with server: true: the actions that poll, retry or debounce on
the client run once there, and start no timers. After rendering, dispose it with
store.dispose(). See Server-side rendering for the
details, Next.js, streaming, and the persistor.
Try it out
Next, let's see how to access the store's state from any component.