Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save sumartoyo/8383479e7f29a2cd3e9f480f6e8fa094 to your computer and use it in GitHub Desktop.
Save sumartoyo/8383479e7f29a2cd3e9f480f6e8fa094 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.

@hassansw
Copy link

Any updates to this post? I prefer using Just JavaScript rather than TypeScript, if there are any changes do update this Post, Thanks

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