Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save hassansw/8111bf1af90404ced47714cab3f17df1 to your computer and use it in GitHub Desktop.
Save hassansw/8111bf1af90404ced47714cab3f17df1 to your computer and use it in GitHub Desktop.
Using zustand Like Normal JavaScript Thing

Global state management in React can be a foreign concept for new programmers. Over the years, we have met reducers, action types, atoms, etc. I have a friend that wants to learn web development, and I imagine it would be very difficult to teach him about these concepts.

zustand is a simple, straightforward, and un-opinionated library for global state management. Because of those traits, I am able to utilize it to manage global state like normal JavaScript thing. What I mean by "normal JavaScript thing" is there is no foreign concept involved in here. It's just a bunch of normal variables, normal functions, and occasionally normal React component. I hope my friend can understand global state management better and faster with this library.

Actualy there is another reason why I did this: Code examples in zustand documentations put functions inside the state, and I found that very... odd?

Managing bear (it's actually a counter, not an actual bear)

The store:

// stores/bear.js

import create from 'zustand';

const bearStore = create(() => ({ bear: 0 }));

export const useBear = () => bearStore((state) => state.bear);
export const getBear = () => bearStore.getState().bear;
const setBear = (setter) => bearStore.setState((state) => ({
  bear: typeof setter === 'function' ? setter(state.bear) : setter,
}));

export const increasePopulation = () => {
  setBear((bear) => bear + 1);
};

export const removeAllBears = () => {
  setBear(0);
};

The components:

import { useBear, increasePopulation, removeAllBears } from './stores/bear';

function BearCounter() {
  const bear = useBear();
  return (
    <p>{bear} around here ...</p>
  );
}

function Controls() {
  return (
    <>
      <p><button onClick={increasePopulation}>one up</button></p>
      <p><button onClick={removeAllBears}>clear</button></p>
    </>
  );
}

The classic todos

The store

// stores/todos.js

import create from 'zustand';

const todosStore = create(() => ({ todos: [] }));

// alright this part below is a boilerplate. surely we could create a simple helper for this.
export const useTodos = () => todosStore((state) => state.todos);
export const getTodos = () => todosStore.getState().todos;
const setTodos = (setter) => todosStore.setState((state) => ({
  todos: typeof setter === 'function' ? setter(state.todos) : setter,
}));

const createTodo = (text) => {
  return {
    id: Math.random(),
    text,
  };
}

export const addTodo = (text) => {
  setTodos((todos) => todos.concat(createTodo(text)));
};

export const removeTodo = (id) => {
  const todos = getTodos();
  const index = todos.findIndex((todo) => todo.id === id);
  setTodos([ ...todos.slice(0, index), ...todos.slice(index + 1) ]);
};

The component

import { useState } from 'react';
import { useTodos, addTodo, removeTodo } from './stores/todos';

function TodoList() {
  const todos = useTodos();
  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo.id}>
          <span>{todo.text}</span>
          <button onClick={() => removeTodo(todo.id)}></button>
        </li>
      ))}
    </ul>
  );
}

function TodoCreator() {
  const [inputValue, setInputValue] = useState('');

  const addItem = () => {
    addTodo(inputValue);
    setInputValue('');
  };

  return (
    <>
      <p>
        <input
          type="text"
          value={inputValue}
          onChange={(event) => setInputValue(event.target.value)}
        />
      </p>
      <p><button onClick={addItem}>Add</button></p>
    </>
  );
}

Epilogue

I hope the code can explain what I mean by normal-javascript-thingy. Normal variables. Normal functions. We can test and debug them like we usually do to normal functions. We can mock them like normal javascript things. And for me, I can teach my friend in normal JavaScript language with minimal foreign concepts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment