Эта статья — перевод оригинальной статьи Madushika Perera "Zustand’s Guide to Simple State Management"
Также я веду телеграм канал “Frontend по-флотски”, где рассказываю про интересные вещи из мира разработки интерфейсов.
Вступление
За последние несколько лет управление состоянием в React претерпело значительные изменения. Многие перешли с Flux на Redux и ищут еще более простые решения. Кроме того, появление React Hooks открыло новые возможности для управления состоянием.
Некоторые из новых библиотек управления состоянием, которые появились на горизонте, — это Recoil, Jotai, Radio Active state и Zustand.
В этой статье я расскажу о Zustand, который предоставляет легкий и простой способ управления состоянием в React.
Что такое Zustand?
Zustand — это библиотека управления состоянием с открытым исходным кодом, разработанная создателями Jotai и React-spring (лучшая библиотека анимации React). Он уже набрал более чем 50 000 еженедельных загрузок.
На данный момент это одна из самых легких библиотек управления состоянием, ее размер составляет 1,5 КБ. Несмотря на то, что она легкая, она решает некоторые важные проблемы, такие как:
Чем он отличается от остальных?
Вы можете задаться вопросом, почему те же создатели Jotai создали Zustand? Это два противоположных подхода. Jotai стремится предоставить простое решение для useState и useContext, создавая атомарное состояние (точно так же, как Recoil).
Zustand использует внешнее хранилище и предоставляет несколько хуков для его подключения.
Тогда, разве это не больше похоже на Redux? Если мы сравним Zustand с Redux, одно из основных отличий — это требуемый шаблонный код. Zustand требует меньше из-за своего самоуверенного подхода. Кроме того, сочетание следующих функций делает его уникальным;
Он не оборачивает приложение в провайдеров контекста.
Он позволяет добавлять функции подписчика, чтобы компоненты могли привязываться к состоянию без повторного рендеринга при мимолётных обновлениях.
Использует мемоизированные селекторы, а функция React useCallback API позволяет оптимизировать производительность в параллельном режиме.
Он довольно хорошо поддерживает middlewar. Вы можете подключить его к таким библиотекам, как Immer, чтобы сократить код в редьюсерах и внести изменения во вложенное состояние.
Начинаем с React и Zustand
Давайте посмотрим, как Zustand работает с React. Чтобы продемонстрировать его возможности, я создам небольшое приложение Pokemon. Это приложение состоит из хранилища, компонента списка и формы ввода, которая обрабатывает ввод пользователя.
Шаг 1. Установка
Установка Zustand так же проста, как установка любого из пакетов npm. Давайте установим его с помощью npm или yarn.
npm install zustand
yarn add zustand
Шаг 2. Создаём хранилище
Далее давайте создадим хранилище, как и в любой другой библиотеке управления состоянием.
import create from "zustand";
const useStore = create((set) => ({
pokemons: [{ id: 1, name: "Bulbasaur" },
{ id: 2, name: "Ivysaur" },
{ id: 3, name: "Venusaur" },
{ id: 4, name: "Charmander" },
{ id: 5, name: "Charmeleon" },
],
addPokemons: (pokemon) =>
set((state) => ({
pokemons: [
{ name: pokemon.name, id: Math.random() * 100 },
...state.pokemons,
]})),
removePokemon: (id) =>
set((state) => ({
pokemons: state.pokemons.filter((pokemon) => pokemon.id !== id),
})),
}));
export default useStore;
Хранилище создается с помощью create API, и экшены могут быть созданы, как показано выше. Доступ к этому хранилищу можно получить через приложение без использования какого-либо провайдера HOC (компонента более высокого порядка), как в Redux.
Шаг 3. Получаем доступ к хранилищу
Zustand не полностью привязан к React. Его можно использовать с любыми другими библиотеками, такими как Vue или Angular. Давайте посмотрим, как мы можем получить доступ к хранилищу из компонента.
Доступ к состоянию хранилища и отображение данных в виде списка
import useStore from "../store";
function List() {
const pokemons = useStore((state) => state.pokemons);
const removePokemon = useStore((state) => state.removePokemon);
return (
<div className="row">
<div className="col-md-4"></div>
<div className="col-md-4">
<ul>{pokemons.map((pokemon) => (
<li key={pokemon.id}>
<div className="row">
<div className="col-md-6">{pokemon.name} </div>
<div className="col-md-6">
<button className="btn btn-outline-secondary btn-sm"
onClick={(e) => removePokemon(pokemon.id)}>X
</button>
</div>
</div>
</li>
))}
</ul>
</div>
<div className="col-md-4"></div>
</div>);
}
export default List;
Обновляем состояния с помощью формы
import { useState } from "react";
import useStore from "../store";
function Form() {
const [name, setName] = useState("");
const addPokemons = useStore((state) => state.addPokemons);
const onChange = (e) => {
setName(e.target.value);
};
const addPokemon = () => {
addPokemons({ name: name });
clear();
};
const clear = () => setName("");
return (
<div className="row">
<div className="col-md-2"></div>
<div className="col-md-6">
<input
type="text"
className="form-control"
onChange={onChange}
value={name}
></input>
</div>
<div className="col-md-2">
<button
className="btn btn-outline-primary"
onClick={(e) => addPokemon()}
>
Add
</button>
</div>
<div className="col-md-2"></div>
</div>
);
}
export default Form;
Как видите, Zustand намного точнее и проще, чем Redux, Recoil или Jotai.
Шаг 4. Обработка асинхронных экшенов
Одним из реальных применений действия Zustand является получение данных через REST API. Эти экшены мы должны выполнять асинхронно.
import axios from "axios";
const useStore = create(set => ({
pokemons: [],
getPokemons: async ()=> {
const response = await axios.get('')
set({ pokemons: response.data })
}
}))
Асинхронный экшен можно обработать, используя async/await в JavaScript. В приведенном выше примере вы можете увидеть, как асинхронные экшены запускаются через axios.
Шаг 5: Middleware для Zustand
Zustand имеет несколько уникальных middleware'ов из коробки. Наиболее известными middleware'ами являются dev tools (использующие инструменты разработки Redux) и Persist, которые могут сохранять данные в браузере.
let useStore : (set)=>{
/* state and actions */
};
useStore = persist(useStore, { name: 'Bulbasaur' })
useStore = devtools(useStore)
export default useStore = create(useStore);
С Zustand вы также можете создать собственный middleware и плагин.
Заключение
В заключение, библиотека Zustand — одна из самых легких библиотек управления состоянием. Он также обеспечивает гибкость для расширения своей функциональности с помощью подключаемых модулей и middlerware для улучшения опыта разработки.
Например, Zustand позволяет получить доступ к хранилищу вне React и совместим с Redux DevTools, Persist и поддерживает React Hooks, TypeScript и т. д.
Таким образом, Zustand выглядит отличным кандидатом на пост управления состоянием в приложении. Простота библиотеки также делает ее хорошим вариантом для начинающих.
Наконец, спасибо, что нашли время, чтобы прочитать это. Я хотел бы видеть ваши вопросы и комментарии ниже.
Ваше здоровье!