The state of React's state management for me
Akuma Isaac Akuma
Posted on November 28, 2020
Initially, Reacts global and components level state managements was once the most time-consuming part whenever I start a new project, It's always the "which one to use?" question.
Should I use redux or redux-saga or mobx-react or mobx-state-tree or several other packages, but haven't gone back and forth Reacts own Context API combined with Reducer has been the real winner for me.
No external package or no need to state learning any package APIs.
So let me share what my store looks like, both in ReactNative and Web.
// ~/lib/store.tsx
import { createContext, Dispatch } from "react";
export interface IState {
user: User;
notifications: Array<INotification>;
}
export type Actions = {
kind: keyof IState;
payload?: any;
};
export function appReducer(state: IState, action: Actions) {
state = { ...state, [action.kind]: action.payload };
return state;
}
interface IContextProps {
state: IState;
dispatch: Dispatch<Actions>;
}
export const AppContext = createContext({} as IContextProps);
export const AppStateProvider = ({ children }) => {
const [state, dispatch] = useReducer(appReducer, {
user: null,
notifications: [],
});
return <AppContext.Provider value={{ state, dispatch }}>{children}</AppContext.Provider>;
};
Then register the AppStateProvider at your app root
// ~/pages/_app.tsx
import { StateProvider } from "~/lib/store";
export default function App({ Component, pageProps }) {
return (
<AppStateProvider>
<Component {...pageProps} />
</AppStateProvider>
);
}
Then usage will look like this
// ~/pages/index.tsx
import React, { useContext, useState } from "react";
export default function HomePage() {
const { state, dispatch } = useContext(AppContext);
const [form, setForm] = useState({ name: "", email: "" });
function onChange(ev: React.FormEvent<{}>) {
const target = ev.target as HTMLInputElement;
const value = target.type === "checkbox" ? target.checked : target.value;
const name = target.name;
setForm((v) => ({ ...v, [name]: value }));
}
function login(ev: React.FormEvent<HTMLFormElement>) {
ev.preventDefault();
if (Object.values(form).every(Boolean)) {
dispatch({ kind: "user", payload: form });
} else {
alert("Please fill the form well");
}
}
return (
<div>
{state.user ? (
<div>
<hi>Welcome {state.user?.name}</hi>
</div>
) : (
<div>
<h1>Login</h1>
<form action="" method="post" onSubmit={login}>
<section>
<label htmlFor="name">Name</label>
<div>
<input name="name" id="name" value={form.name} onChange={onChange} />
</div>
</section>
<section>
<label htmlFor="email">Email</label>
<div>
<input name="email" id="email" value={form.email} onChange={onChange} />
</div>
</section>
<button>Login</button>
</form>
</div>
)}
</div>
);
}
And also know that the dispatch state key kind
is well-typed
The end!.
I hope this helps.
Posted on November 28, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.