The state of React's state management for me

akumzy

Akuma Isaac Akuma

Posted on November 28, 2020

The state of React's state management for me

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>;
};
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}

Enter fullscreen mode Exit fullscreen mode

And also know that the dispatch state key kind is well-typed

dispatch screenshot

The end!.
I hope this helps.

💖 💪 🙅 🚩
akumzy
Akuma Isaac Akuma

Posted on November 28, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related