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?
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 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>
</>
);
}
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.
Any updates to this post? I prefer using Just JavaScript rather than TypeScript, if there are any changes do update this Post, Thanks