Самая утомительное при реализации Redux — это написание того объёма шаблонного кода, который нужен для обработки потока данных между компонентами и хранилищем Redux. Сам Redux был создан по примеру появившейся в 2014 году архитектуры потока данных Flux.
С момента выхода React произошёл переход от компонентов класса к функциональным компонентам с хуками. Несмотря на все преимущества Redux и Flux (это замечательные инструменты), возможно, стоит задействовать новый шаблон, который в полной мере раскрывает возможности React.
Jotai — это библиотека управления состоянием для React, которая избавит вас от мучений с шаблонным кодом благодаря своему минималистичному API. Причём с Jotai никаких экшенов, редьюсеров или диспетчеров создавать не придётся!
Специфика работы Jotai очень схожа с React Context и Recoil. Быстро разобраться с ней не составит большого труда, даже если вам не знакомы эти названия, потому что эта библиотека очень проста.
Как работает Jotai
Для начала работы с Jotai первым делом нужно установить эту библиотеку:
npm install jotai
# или
yarn add jotai
Jotai заменяет значения локального состояния в компонентах React на объекты atom
, которые содержат часть состояния. Затем этот объект atom
будет передан в хук useAtom()
, чтобы компоненты могли использовать и обновлять значение, которое в тот момент будет в нём храниться. Объект atom
создаётся с помощью вызова функции atom
:
import { atom } from 'jotai'
const countAtom = atom(0)
const countryAtom = atom('Japan')
Теперь эти atom (0
и Japan
) хранятся внутри Jotai в компоненте Provider
, который используется для обёртывания компонентов React:
import { Provider } from 'jotai'
const Root = () => (
<Provider>
<App />
</Provider>
)
В этом примере все компоненты, обёрнутые в Provider
, теперь имеют доступ к объектам atom
в Jotai и обновляют их.
Доступ к atom
получается с помощью хука useAtom
, возвращающего значение atom
и функцию обновления. Очень похоже на хук useState()
:
import { useAtom } from 'jotai'
function Counter() {
const [count, setCount] = useAtom(countAtom)
return (
<>
<h1>{count} </h1>
<button onClick={() => setCount((value) => value + 1)}>one up</button>
</>
);
Вот и всё! atom
вызывается из любых других компонентов, лишь бы они находились внутри Provider
в дереве DOM.
По сравнению со структурой приложения React-Redux, React-Jotai намного проще. Вот как выглядит типичная структура React-Redux:
А вот простая схема, иллюстрирующая работу Jotai:
Для просмотра шаблона Jotai доступна интерактивная демо-версия. Рекомендуется выполнить объявление atom
в отдельном файле: так эти atom
смогут импортироваться в любые компоненты consumer
.
Рефакторинг приложения на Redux для использования Jotai
Трудность выполнения рефакторинга приложения на Redux для использования Jotai зависит от сложности самого приложения. За образец возьмите эти идентичные примеры:
Выполняя рефакторинг, первым делом обычно меняют Provider
в Redux на Provider
в Jotai. С этого:
import { createStore } from "redux";
import { Provider } from "react-redux";
import App from "./App";
const store = createStore(reducer);
const Main = () => (
<Provider store={store}>
<App />
</Provider>
)
На этот:
import { Provider } from "jotai";
import App from "./App";
const Main = () => (
<Provider>
<App />
</Provider>
)
Больше нет необходимости передавать store
в Provider
, но для замены механизма store
нужно создать atoms
. Если у вас в редьюсере применяется defaultState
, используйте его для создания atoms
:
const defaultState = {
isPrimary: true,
};
const reducer = (state = defaultState, action) => {
// остальная часть кода опущена...
}
Этот редьюсер можно заменить на простую функцию atom
:
import { atom } from "jotai";
export const isPrimaryAtom = atom(true)
Разобравшись с той частью, что относится к Provider
и Store
, для завершения рефакторинга нам остаётся только заменить Dispatcher
и Action
. Общий шаблон Dispatcher
должен выглядеть так:
import { useSelector, useDispatch } from "react-redux";
function App() {
const isPrimary = useSelector((state) => state.isPrimary);
const dispatch = useDispatch();
const title = isPrimary ? "Primary" : "Secondary";
return (
<StyledButton
isPrimary={isPrimary}
onClick={() => {
dispatch({ type: "TOOGLE_BUTTON", payload: !isPrimary });
}}
>
Нужно заменить импорт на useAtom
из Jotai и для замены Dispatcher
использовать возвращённое состояние из функции обновления:
import { useAtom } from "jotai";
import { isPrimaryAtom } from "./Atoms";
function App() {
const [isPrimary, setIsPrimary] = useAtom(isPrimaryAtom);
const title = isPrimary ? "Primary" : "Secondary";
return (
<StyledButton
isPrimary={isPrimary}
onClick={() => {
setIsPrimary(!isPrimary);
}}
Чем сложнее приложение, тем тяжелее его рефакторинг и переключение библиотеки управления состоянием. Но приведённые в этой статье рекомендации должны помочь в создании плана рефакторинга.
Заключение
Jotai и Recoil прекрасно демонстрируют то, как хуки повлияли на разработку приложений на React. Несмотря на муторный шаблонный код, Redux продолжает быть самой известной библиотекой управления состоянием, потому что её преимущества весомее затрат. Но с Jotai эти преимущества теперь получают без затрат.
Тем не менее это не означает, что Redux больше не нужна. Многие годы её безуспешно пытались заменить другие инструменты управления состоянием. В случае если приложению требуется ручной контроль над тем, когда, почему и как изменяется состояние, Redux будет незаменима. С другой стороны, если вам нужен простой инструмент управления состоянием для использования этого состояния глобально, то Jotai может быть отличной альтернативой.
Читайте также:
- Три функции JavaScript для освоения метода Reduce
- 20 сокращений JavaScript, которые сэкономят ваше время
- Как увеличить производительность CSS-in-JS в 175 раз
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи Nathan Sebhastian: Redux-Free State Management with Jotai