App Setup
Demo
A Simple Incrementor
import { createReactRecorder } from 'diagon-react';
import React, { FC, memo } from 'react';
const { useSnap, useMutator } = createReactRecorder();
const state = {
counter: 0
};
export const Incrementor: FC = memo(() => {
const counter = useSnap(state, state => state.counter);
const increment = useMutator(state, state => state.counter++);
return (
<div>
<div>value: {counter}</div>
<button onClick={increment}>Click me</button>
</div>
);
});
export const App: FC = () => <Incrementor />;
Setting up a quick app with global state is very straightforward. Your application state is a plain JavaScript object.
First, you need to define a global Recorder
that is shared with every component in your app. This object is your main way to make changes to your state and trigger optimized re-renders in your application, and the recorder has member functions that define all the hooks you need for your components.
Here you see a simple counter component showing the main pattern when using Diagon with React:
- Get access to the state you want to use. Any state source will work!
- You can use a global state, or props, or any other JavaScript object is perfectly fine to use. They don't have to be in your root state and can come from anywhere!
- Subscribe to the properties of the state that you want to observe with
useSnap
. When those properties change, your component will re-render. - Define mutators with
useMutator
to make modifications to your state. - Wrap your components in
memo
and you're good!
StoreProvider (Optional)
You may also use Diagon through React's Context functionality with the StoreProvider.
It is completely optional but if you want a more traditional way of accessing your state and only using directly imported hooks from Diagon, here you go.
Create your State
import { createReactRecorder, getTypedUseRootState } from 'diagon-react';
export const recorder = createReactRecorder();
export const createRootState = () => ({
counter: 0
});
export type RootState = ReturnType<typeof createRootState>;
export const useAppState = getTypedUseRootState<RootState>();
For TypeScript convenience, there is getTypedUseRootState
to wrap the useRootState
hook so that it will return a strongly typed version of the state for your components.
Create a Store
import { StoreProvider } from 'diagon-react';
import React, { FC, useState } from 'react';
import { createRootState, recorder } from './state';
export const App: FC = () => {
const [store] = useState(() => ({state: createRootState(), recorder}));
return (
<StoreProvider {...store}>
<Incrementor/>
</StoreProvider>
);
};
At the top level of your app, you need a StoreProvider
that will enable support for all of Diagon's hooks. You simply pass it an object containing your state and the Recorder
you created earlier.
The state is optional, but since most React applications tend to have a single state store, Diagon includes the useRootState
hook to grab the state you passed in here.
Create a Component
import { useMutator, useSnap } from 'diagon-react';
import React, { FC } from 'react';
import { useAppState } from './state';
export const Incrementor: FC = React.memo(() => {
const state = useAppState();
const counter = useSnap(state, state => state.counter);
const increment = useMutator(state, state => state.counter++);
return (
<div>
<div>value: {counter}</div>
<button onClick={increment}>Click me</button>
</div>
);
});
When using the store provider you simply do similar to the above, but tend to access your state with useAppState
.
- Get access to the state you want to use. Any state source will work!
- You can get the root state from the
useAppState
hook you defined. - Props, or any other JavaScript are perfectly fine to use. They don't have to be in your root state and can come from anywhere!
- You can get the root state from the
- Subscribe to the properties of the state that you want to observe with
useSnap
. When those properties change, your component will re-render. - Define mutators with
useMutator
to make modifications to your state.