Create React App + Redux
CRA предоставляет готовый официальный шаблон с уже подключенным Redux Toolkit. Для этого нужно использовать опцию
Можно даже с typescript, если вы уже его используете (я пока нет):
UPD: да, и конечно тут уже есть интеграция с Redux DevTools
#redux #управлениесостоянием #инструменты
CRA предоставляет готовый официальный шаблон с уже подключенным Redux Toolkit. Для этого нужно использовать опцию
--template
:npx create-react-app my-app --template reduxТо есть ничего дополнительно подключать не нужно, эта функциональность уже есть в create-react-app из коробки.
Можно даже с typescript, если вы уже его используете (я пока нет):
npx create-react-app my-app --template redux-typescriptВ созданном проекте уже есть папка
features
и даже готовый пример features/counter
с примерами использования методов createSlice, createAsyncThunk и configureStore.UPD: да, и конечно тут уже есть интеграция с Redux DevTools
#redux #управлениесостоянием #инструменты
👍6
После довольно долгого перерыва будет полезно быстро вспомнить, что мы уже знаем о Redux Toolkit.
Сделаем это на примере простого демо-проекта Счетчика из официальной документации Redux:
🗂 Разделение на фичи
Хорошая практика - делить общее глобальное хранилище на несколько частей, соответствующих логическому разделению функционала приложения. Например, в одном из предыдущих проектов (TODO-лист) мы разделили хранилище на две части:
А в Счетчике фича всего одна - собственно логика счетчика, это тоже нормально.
Документация рекомендует разносить такие фичи по отдельным папкам - в каждой собственный слайс (редьюсер + экшены) и свои компоненты.
🔪 Создание слайсов
Слайс создается с помощью функции createSlice из Redux Toolkit.
Пример для счетчика в файле counterSlice.js.
В Redux Toolkit мы уже не мыслим отдельными понятиями редьюсер и экшены, тут у нас все сразу вместе (и если подумать, это действительно удобнее). По сути мы перечисляем типы экшенов и для каждого указываем логику обработки - такой маленький редьюсер для одного экшена.
При этом под капотом генерируются action creators. Они доступны в поле
⏳ Thunks
Для thunk creators вообще-то существует отдельная функция createAsyncThunk, но в этом вводном демо-проекте авторы используют привычный способ - просто создают функцию
Но при желании с помощью
🗄 Создание хранилища
Хранилище создается в файле app/store.js.
Здесь импортируются все необходимые редьюсеры (тут только один) и объединяются с помощью функции configureStore. Под капотом тут подключаются разные полезные миддлвары, включая redux-thunk и redux-devtools.
🧲 Подключение хранилища к приложению
За "мост" между Redux и React отвечает пакет react-redux, у которого есть компонент
✋ Доступ к хранилищу из компонентов
Для получения данных из хранилища используются функции-селекторы, которые знают, как добраться до нужных данных. Они находятся в том же файле, что и слайс, максимально близко к данным, собственно.
А в компонентах мы используем хук
Пример в компоненте Counter.
Redux Toolkit в целом много оптимизует под капотом, но селекторы можно оптимизировать дополнительно с помощью функции createSelector (в Счетчике она не используется).
🪃 Отправка экшенов и thunks
Для отправки экшенов используем хук
#документация #управлениесостоянием #redux #примерыкода
Сделаем это на примере простого демо-проекта Счетчика из официальной документации Redux:
🗂 Разделение на фичи
Хорошая практика - делить общее глобальное хранилище на несколько частей, соответствующих логическому разделению функционала приложения. Например, в одном из предыдущих проектов (TODO-лист) мы разделили хранилище на две части:
todos
и filters
. В первой были все операции, связанные со списком (CRUD), во втором - вся логика фильтрации. Они частично пересекаются (отфильтрованный список), но в целом это две разные функциональности.А в Счетчике фича всего одна - собственно логика счетчика, это тоже нормально.
Документация рекомендует разносить такие фичи по отдельным папкам - в каждой собственный слайс (редьюсер + экшены) и свои компоненты.
🔪 Создание слайсов
Слайс создается с помощью функции createSlice из Redux Toolkit.
Пример для счетчика в файле counterSlice.js.
В Redux Toolkit мы уже не мыслим отдельными понятиями редьюсер и экшены, тут у нас все сразу вместе (и если подумать, это действительно удобнее). По сути мы перечисляем типы экшенов и для каждого указываем логику обработки - такой маленький редьюсер для одного экшена.
При этом под капотом генерируются action creators. Они доступны в поле
counterSlice.actions
.⏳ Thunks
Для thunk creators вообще-то существует отдельная функция createAsyncThunk, но в этом вводном демо-проекте авторы используют привычный способ - просто создают функцию
incrementAsync
, которая возвращает thunk, без дополнительной интеграции в слайс. Но при желании с помощью
createAsyncThunk
мы можем подключиться к событиям "начала" и "конца" выполнения асинхронной операции.🗄 Создание хранилища
Хранилище создается в файле app/store.js.
Здесь импортируются все необходимые редьюсеры (тут только один) и объединяются с помощью функции configureStore. Под капотом тут подключаются разные полезные миддлвары, включая redux-thunk и redux-devtools.
🧲 Подключение хранилища к приложению
За "мост" между Redux и React отвечает пакет react-redux, у которого есть компонент
Provider
, который обеспечивает проброс хранилища до всех заинтересованных компонентов (используется контекст).✋ Доступ к хранилищу из компонентов
Для получения данных из хранилища используются функции-селекторы, которые знают, как добраться до нужных данных. Они находятся в том же файле, что и слайс, максимально близко к данным, собственно.
А в компонентах мы используем хук
useSelector
(из пакета react-redux), которому передаем нужный селектор. Пример в компоненте Counter.
Redux Toolkit в целом много оптимизует под капотом, но селекторы можно оптимизировать дополнительно с помощью функции createSelector (в Счетчике она не используется).
🪃 Отправка экшенов и thunks
Для отправки экшенов используем хук
useDispatch
(из пакета react-redux). По сути это обращение к методу store.dispatch
. В него передаем или объект экшена, или thunk.#документация #управлениесостоянием #redux #примерыкода
CodeSandbox
redux-essentials-counter-example - CodeSandbox
redux-essentials-counter-example using @reduxjs/toolkit, @testing-library/jest-dom, @testing-library/react, @testing-library/user-event, react, react-dom, react-redux, react-scripts
👍2
Новый проект
Наконец-то начинаю работу над новым проектом в рамках руководства Redux Essentials, которое должно научить меня лучшим практикам Redux.
Готовый проект выглядит так: https://codesandbox.io/s/github/reduxjs/redux-essentials-example-app/tree/tutorial-steps
Тут три вкладки:
- Posts - лента постов + форма для создания новой записи. Отсюда можно перейти на страницу отдельного поста и отредактировать его.
- Users - список пользователей. У каждого пользователя есть своя страница со списком его записей.
- Notifications - лента уведомлений, которую можно обновлять.
В демо-версии кое-что не работает или работает через раз, но это не имеет значения, все равно будем все переписывать с нуля :)
Первый разбор
Очевидно, что в проекте три основных фичи: посты, пользователи и уведомления. Для каждой из них, вероятно, нужно будет создать отдельный слайс.
Все данные приходят с сервера, а изменения синхронизируются с ним, значит, придется использовать какой-то api, слать запросы и асинхронно их обрабатывать. Тут нам вероятно понадобятся thunks. Спойлер: для api используется, очевидно, RTK Query, вот и повод с ним познакомиться.
Посты
Есть форма для добавления поста, ее состояние будет храниться локально. При отправке будем отправлять thunk. Понадобится также отслеживать начало и конец выполнения, чтобы отображать состояние отправки.
Есть список постов, а у постов есть реакции, скорее всего, их следует хранить в данных самого поста, так как они несамостоятельны.
Можно просматривать каждый пост, значит, нужно получать его данные по какому-то идентификатору.
Пост можно отредактировать, тут все по аналогии с формой добавления.
Пользователи
Есть список пользователей (имя и ссылка на отдельную страницу), а также список записей, созданных пользователем.
Уведомления
Опять же обычный список. Плюс есть кнопка Refresh Notifications, которая подгружает новую порцию элементов. Их нужно будет добавить в существующий массив.
Свежие уведомления выделяются фоном.
Начало работы
Итак, первый взгляд бросили. Теперь создаем новый проект и начинаем работать.
Для этого либо используем CRA с шаблоном redux:
#redux #управлениесостоянием #документация
Наконец-то начинаю работу над новым проектом в рамках руководства Redux Essentials, которое должно научить меня лучшим практикам Redux.
Готовый проект выглядит так: https://codesandbox.io/s/github/reduxjs/redux-essentials-example-app/tree/tutorial-steps
Тут три вкладки:
- Posts - лента постов + форма для создания новой записи. Отсюда можно перейти на страницу отдельного поста и отредактировать его.
- Users - список пользователей. У каждого пользователя есть своя страница со списком его записей.
- Notifications - лента уведомлений, которую можно обновлять.
В демо-версии кое-что не работает или работает через раз, но это не имеет значения, все равно будем все переписывать с нуля :)
Первый разбор
Очевидно, что в проекте три основных фичи: посты, пользователи и уведомления. Для каждой из них, вероятно, нужно будет создать отдельный слайс.
Все данные приходят с сервера, а изменения синхронизируются с ним, значит, придется использовать какой-то api, слать запросы и асинхронно их обрабатывать. Тут нам вероятно понадобятся thunks. Спойлер: для api используется, очевидно, RTK Query, вот и повод с ним познакомиться.
Посты
Есть форма для добавления поста, ее состояние будет храниться локально. При отправке будем отправлять thunk. Понадобится также отслеживать начало и конец выполнения, чтобы отображать состояние отправки.
Есть список постов, а у постов есть реакции, скорее всего, их следует хранить в данных самого поста, так как они несамостоятельны.
Можно просматривать каждый пост, значит, нужно получать его данные по какому-то идентификатору.
Пост можно отредактировать, тут все по аналогии с формой добавления.
Пользователи
Есть список пользователей (имя и ссылка на отдельную страницу), а также список записей, созданных пользователем.
Уведомления
Опять же обычный список. Плюс есть кнопка Refresh Notifications, которая подгружает новую порцию элементов. Их нужно будет добавить в существующий массив.
Свежие уведомления выделяются фоном.
Начало работы
Итак, первый взгляд бросили. Теперь создаем новый проект и начинаем работать.
Для этого либо используем CRA с шаблоном redux:
npx create-react-app my-app --template reduxЛибо подключаем по отдельности react-redux и @reduxjs/toolkit.
#redux #управлениесостоянием #документация
CodeSandbox
redux-essentials-example - CodeSandbox
redux-essentials-example using @faker-js/faker, @mswjs/data, @reduxjs/toolkit, classnames, date-fns, mock-socket, msw, react, react-dom
👍2🔥1
Redux Essentials 1. Лента статей
Начинаем с вывода списка статей. Тут все очень просто, мы такое уже не раз делали.
https://codesandbox.io/s/redux-essentials-posts-react-junior-6cyh18?file=/src/App.js
Как и предполагалось, создаем отдельную папку features/posts, а в ней файл postsSlice.js. Используем функцию
Сразу здесь же создаем селектор
В файле app/store.js создаем хранилище (функция
В файле App.js подготавливаем структуру приложения. У нас будет много страниц, поэтому подключаем react-router-dom. Пока роут только один - индексный. Тут будет выводиться лента постов, а затем еще и форма создания поста.
Компонент ленты постов - features/posts/PostsList.js. Чтобы получить список, используем хук
#redux #управлениесостоянием #документация #примерыкода
Начинаем с вывода списка статей. Тут все очень просто, мы такое уже не раз делали.
https://codesandbox.io/s/redux-essentials-posts-react-junior-6cyh18?file=/src/App.js
Как и предполагалось, создаем отдельную папку features/posts, а в ней файл postsSlice.js. Используем функцию
createSlice
- пока без всяких редьюсеров, только с начальным состоянием. Сразу здесь же создаем селектор
getPosts
для получения списка статей.В файле app/store.js создаем хранилище (функция
createStore
), подключаем созданный слайс. В файле App.js подготавливаем структуру приложения. У нас будет много страниц, поэтому подключаем react-router-dom. Пока роут только один - индексный. Тут будет выводиться лента постов, а затем еще и форма создания поста.
Компонент ленты постов - features/posts/PostsList.js. Чтобы получить список, используем хук
useSelector
.#redux #управлениесостоянием #документация #примерыкода
CodeSandbox
Redux Essentials. Posts. React Junior - CodeSandbox
Redux Essentials. Posts. React Junior by furrycat.web using @reduxjs/toolkit, react, react-dom, react-redux, react-router-dom, react-scripts, styled-components
👍4
Redux Essentials 2. Добавление статей
Важно: Появились проблемы с обновленным React 18, поэтому пока переключаюсь на версию 17.0.2.
https://codesandbox.io/s/redux-essentials-add-post-react-junior-5wmcg3?file=/src/App.js
Здесь все тоже знакомо.
Для внесения изменений в состояние нам потребуется экшен -
Важно: Внутри функции
Redux Toolkit автоматически генерирует нам action creator с таким же названием
Добавляем форму создания статьи - компонент features/posts/AddPostForm.js. Выводим ее в компоненте
Все состояние формы хранится внутри компонента. При отправке вызываем метод
#redux #управлениесостоянием #документация #примерыкода
Важно: Появились проблемы с обновленным React 18, поэтому пока переключаюсь на версию 17.0.2.
https://codesandbox.io/s/redux-essentials-add-post-react-junior-5wmcg3?file=/src/App.js
Здесь все тоже знакомо.
Для внесения изменений в состояние нам потребуется экшен -
postAdded
. Добавляем его обработчик в postsSlice
, в секцию reducers
. При возникновении экшена просто пушим его данные в state
.Важно: Внутри функции
createSlice
допустимо мутировать состояние, так как оно специально обрабатывается. Redux Toolkit автоматически генерирует нам action creator с таким же названием
postAdded
, который можно забрать из postSlice.actions
.Добавляем форму создания статьи - компонент features/posts/AddPostForm.js. Выводим ее в компоненте
App
.Все состояние формы хранится внутри компонента. При отправке вызываем метод
dispatch
, чтобы отправить экшен в хранилище (берем из хука useDispatch
). Сам экшен генерируем с помощью креатора из предыдущего абзаца.#redux #управлениесостоянием #документация #примерыкода
CodeSandbox
Redux Essentials. Add post. React Junior - CodeSandbox
Redux Essentials. Add post. React Junior by furrycat.web using @reduxjs/toolkit, react, react-dom, react-redux, react-router-dom, react-scripts, styled-components
👍4
Кстати, в пакете @reduxjs/toolkit есть функция
#redux #документация
nanoid
для генерации уникальных идентификаторов.import { nanoid } from "@reduxjs/toolkit";
#redux #документация
👍5
Redux Essentials 3. Страница статьи
Добавляем возможность просмотреть отдельную статью.
https://codesandbox.io/s/redux-essentials-single-post-page-react-junior-3dziwq?file=/src/App.js
Для этого понадобится новый роут вида
Роут будет динамический (с параметром -
Помним, что селектор должен лежать рядом со слайсом, так как он знает, как получать данные из хранилища. В руководстве селекторы объявляются в компонентах.
Если статья с указанным идентификатором не нашлась, выводим сообщение.
Наконец, добавляем ссылки на посты в компоненте
#redux #управлениесостоянием #документация #примерыкода
Добавляем возможность просмотреть отдельную статью.
https://codesandbox.io/s/redux-essentials-single-post-page-react-junior-3dziwq?file=/src/App.js
Для этого понадобится новый роут вида
/posts/123
и компонент SinglePostPage
(лежит в папке features/posts).Роут будет динамический (с параметром -
/posts/:id
), в компонент нужно получить сначала значение этого параметра, чтобы узнать, с какой статьей мы имеем дело (хук useParams
из react-router). А затем - получить данные статьи из хранилища с помощью селектора (getPostData
).Помним, что селектор должен лежать рядом со слайсом, так как он знает, как получать данные из хранилища. В руководстве селекторы объявляются в компонентах.
Если статья с указанным идентификатором не нашлась, выводим сообщение.
Наконец, добавляем ссылки на посты в компоненте
PostsList
.#redux #управлениесостоянием #документация #примерыкода
CodeSandbox
Redux Essentials. Single post page. React Junior - CodeSandbox
Redux Essentials. Single post page. React Junior by furrycat.web using @reduxjs/toolkit, react, react-dom, react-redux, react-router-dom, react-scripts, styled-components
👍3
Redux Essentials 4. Редактирование статьи
https://codesandbox.io/s/redux-essentials-edit-post-react-junior-hbfrh5?file=/src/App.js
Чтобы иметь возможность редактировать статью, нам понадобится:
- новый роут
1) В компоненте получаем id поста из урла с помощью
2) Затем получаем данные поста с помощью селектора
3) Все состояние формы хранится локально.
4) При отправке формы диспатчим экшен с помощью креатора
5) Переходим на роут поста, чтобы увидеть изменения (хук
Так как формы создания и редактирования очень похожи (фактически, это одна и та же форма), появилось большое искушение вынести ее в отдельный компонент - /components/PostForm.js. Он немного избыточен, включает в себя помимо формы еще и текст заголовка и общие стили контейнера, но почему бы и нет.
Что касается экшенов
#redux #управлениесостоянием #документация #примерыкода
https://codesandbox.io/s/redux-essentials-edit-post-react-junior-hbfrh5?file=/src/App.js
Чтобы иметь возможность редактировать статью, нам понадобится:
- новый роут
/editPost/:id
- компонент формы EditPostForm
- новый экшен postUpdated
, чтобы внести изменения в данные1) В компоненте получаем id поста из урла с помощью
useParams
. 2) Затем получаем данные поста с помощью селектора
getPostData
и подставляем их в форму. 3) Все состояние формы хранится локально.
4) При отправке формы диспатчим экшен с помощью креатора
postUpdated
, передавая ему всю необходимую информацию.5) Переходим на роут поста, чтобы увидеть изменения (хук
useNavigate
).Так как формы создания и редактирования очень похожи (фактически, это одна и та же форма), появилось большое искушение вынести ее в отдельный компонент - /components/PostForm.js. Он немного избыточен, включает в себя помимо формы еще и текст заголовка и общие стили контейнера, но почему бы и нет.
Что касается экшенов
postAdded
, postUpdated
. Тут как будто напрашивается нормализованное состояние и createEntityAdapter. Посмотрим, что будет дальше.#redux #управлениесостоянием #документация #примерыкода
CodeSandbox
Redux Essentials. Edit post. React Junior - CodeSandbox
Redux Essentials. Edit post. React Junior by furrycat.web using @reduxjs/toolkit, react, react-dom, react-redux, react-router-dom, react-scripts, styled-components
👍4
Redux Essentials 5. Авторы постов
Следующий шаг - добавляем в приложение пользователей, ведь статьи не сами собой пишутся.
И тут становится понятно, что решение вынести форму создания/редактирования статьи в отдельный компонент было слишком поспешным. В форму создания нужно будет внести изменения, поэтому теперь это два разных компонента, как и было задумано в руководстве.
https://codesandbox.io/s/redux-essentials-users-slice-react-junior-52ltvw?file=/src/App.js
Что делаем?
1. Добавляем новую фичу
2. В форму создания поста добавлям селект для выбора автора (это сделано для простоты и наглядности, в реальном приложении обычно есть механизмы для определения активного пользователя). Список пользователей получаем с помощью
3. Немного изменяем экшен
4. Создаем отдельный компонент
5. Наконец, подключаем этот компонент в каждый пост в ленте
#redux #управлениесостоянием #документация #примерыкода
Следующий шаг - добавляем в приложение пользователей, ведь статьи не сами собой пишутся.
И тут становится понятно, что решение вынести форму создания/редактирования статьи в отдельный компонент было слишком поспешным. В форму создания нужно будет внести изменения, поэтому теперь это два разных компонента, как и было задумано в руководстве.
https://codesandbox.io/s/redux-essentials-users-slice-react-junior-52ltvw?file=/src/App.js
Что делаем?
1. Добавляем новую фичу
users
и новый слайс usersSlice
. Здесь хранится простой список пользователей, даже никаких экшенов нет (пока по крайней мере). Подключаем слайд к хранилищу в файле store.js
. Сразу создаем два селектора - для получения всего списка и для получения отдельного пользователя по идентификатору.2. В форму создания поста добавлям селект для выбора автора (это сделано для простоты и наглядности, в реальном приложении обычно есть механизмы для определения активного пользователя). Список пользователей получаем с помощью
useSelector
. 3. Немного изменяем экшен
posts/postAdded
. Теперь он получает три отдельных параметра вместо одного объекта, поэтому оформляем его в виде массива с полями reducer
и prepare
.4. Создаем отдельный компонент
/posts/PostAuthor.js
, который будет получать id пользователя и выводить его имя.5. Наконец, подключаем этот компонент в каждый пост в ленте
PostsList
и в компонент SinglePostPage
.#redux #управлениесостоянием #документация #примерыкода
CodeSandbox
Redux Essentials. Users slice. React Junior - CodeSandbox
Redux Essentials. Users slice. React Junior by furrycat.web using @reduxjs/toolkit, react, react-dom, react-redux, react-router-dom, react-scripts, styled-components
👍3
Redux Essentials 6. Дата поста
Следующий шаг очень простой и мало связанный, на самом деле, с Redux - добавляем даты создания статей.
https://codesandbox.io/s/redux-essentials-dates-react-junior-y8f6x8?file=/src/App.js
1. Вносим изменения в слайс: добавляем постам новое поле
Важно: Так как в хранилище должны находиться только сериализуемые данные, вместо даты записываем туда строковый
2. Создаем отдельный компонент
3. Выводим дату в списке статей и на странице отдельного поста.
4. В списке дополнительно сортируем статьи по дате, выводя более свежие первыми. Теперь можно добавить новую статью в форме создания, и она окажется первой в списке.
#redux #управлениесостоянием #документация #примерыкода
Следующий шаг очень простой и мало связанный, на самом деле, с Redux - добавляем даты создания статей.
https://codesandbox.io/s/redux-essentials-dates-react-junior-y8f6x8?file=/src/App.js
1. Вносим изменения в слайс: добавляем постам новое поле
date
, устанавливаем текущую дату при создании поста. На прошлом шаге мы разделели редьюсер postAdded
на reducer
и prepare
. Вот как раз в prepare
и добавляется этот новый "подготовительный" функционал.Важно: Так как в хранилище должны находиться только сериализуемые данные, вместо даты записываем туда строковый
timestamp
.2. Создаем отдельный компонент
TimeAgo
для вывода даты (в формате 5 минут назад). Для форматирования используется библиотека date-fns. 3. Выводим дату в списке статей и на странице отдельного поста.
4. В списке дополнительно сортируем статьи по дате, выводя более свежие первыми. Теперь можно добавить новую статью в форме создания, и она окажется первой в списке.
#redux #управлениесостоянием #документация #примерыкода
CodeSandbox
Redux Essentials. Dates. React Junior - CodeSandbox
Redux Essentials. Dates. React Junior by furrycat.web using @reduxjs/toolkit, date-fns, react, react-dom, react-redux, react-router-dom, react-scripts, styled-components
👍1
Redux Essentials 7. Реакции
Добавляем реакции к статьям.
https://codesandbox.io/s/redux-essentials-reactions-react-junior-1p1k32?file=/src/App.js
1. У каждой статьи появляется поле
2. Добавляется новый экшен
3. Добавляется компонент
Механизм реакций, конечно, работает неправильно - сейчас можно ставить сколько угодно лайков, тогда как в реальных приложениях обычно только по одному. Для этого нужно дополнительно сохранять информацию о том, какой юзер что лайкнул. Возможно, это будет реализовано позже.
#redux #управлениесостоянием #документация #примерыкода
Добавляем реакции к статьям.
https://codesandbox.io/s/redux-essentials-reactions-react-junior-1p1k32?file=/src/App.js
1. У каждой статьи появляется поле
reactions
с набором доступных реакций и счетчиком для каждой реакции.2. Добавляется новый экшен
reactionAdded
, который увеличивает счетчик выбранного смайлика.3. Добавляется компонент
ReactionButtons
- набор кнопок с разными реакциями.Механизм реакций, конечно, работает неправильно - сейчас можно ставить сколько угодно лайков, тогда как в реальных приложениях обычно только по одному. Для этого нужно дополнительно сохранять информацию о том, какой юзер что лайкнул. Возможно, это будет реализовано позже.
#redux #управлениесостоянием #документация #примерыкода
CodeSandbox
Redux Essentials. Reactions. React Junior - CodeSandbox
Redux Essentials. Reactions. React Junior by furrycat.web using @reduxjs/toolkit, date-fns, react, react-dom, react-redux, react-router-dom, react-scripts, styled-components
👍2
Forwarded from Cat in Web
Легковесные альтернативы Redux
Статья (англ.): https://blog.openreplay.com/lightweight-alternatives-to-redux
Автор статьи рассказывает, какие инструменты можно использовать для управления глобальным состоянием приложения вместо Redux.
1. Хуки React
Простейший вариант - использовать встроенные хуки. С помощью
2. Zustand
Zustand использует те же flux-принципы, что и Redux. Мы создаем хранилище с помощью функции
3. Jotai
Разработан той же командой, что и Zustand, но использует другой подход - атомарный (atomic). Каждая часть данных оформляется в виде атома с помощью функции
4. Valtio
Подход Valtio базируется на использовании прокси. Мы передаем объект в функцию
В статье есть примеры кода для всех этих решений, можно сформировать общее впечатление и заинтересоваться чем-нибудь.
#redux #react #statemanagement #library
Статья (англ.): https://blog.openreplay.com/lightweight-alternatives-to-redux
Автор статьи рассказывает, какие инструменты можно использовать для управления глобальным состоянием приложения вместо Redux.
1. Хуки React
Простейший вариант - использовать встроенные хуки. С помощью
useReducer
мы выносим состояние приложения в отдельный объект и можем удобно им управлять, а с помощью контекста доставляем этот объект до всех заинтересованных компонентов. Пример.2. Zustand
Zustand использует те же flux-принципы, что и Redux. Мы создаем хранилище с помощью функции
create
и получаем из нее хук useStore
, который можно использовать в компонентах. 3. Jotai
Разработан той же командой, что и Zustand, но использует другой подход - атомарный (atomic). Каждая часть данных оформляется в виде атома с помощью функции
atom
. Для работы с атомами есть хук useAtom
, который работает так же, как useState
. 4. Valtio
Подход Valtio базируется на использовании прокси. Мы передаем объект в функцию
proxy
и дальше можем его мутировать - прокси отслеживает все изменения.В статье есть примеры кода для всех этих решений, можно сформировать общее впечатление и заинтересоваться чем-нибудь.
#redux #react #statemanagement #library
Openreplay
Lightweight Alternatives to Redux
Forget about Redux for a minute and think aboutside the box
👍2
Forwarded from Cat in Web
React World
Развлекалочка на React: https://sfatihk.github.io/react-world/
Скроль страницу и совершай небольшое путешествие с героями любимых фильмов.
А потом можно залезть в исходники и посмотреть, как все это работает: https://github.com/sfatihk/react-world
#react
Развлекалочка на React: https://sfatihk.github.io/react-world/
Скроль страницу и совершай небольшое путешествие с героями любимых фильмов.
А потом можно залезть в исходники и посмотреть, как все это работает: https://github.com/sfatihk/react-world
#react
👍2
Redux Essentials 8. Запрос данных
Теперь сделаем наше приложение более реалистичным - установим связь с "сервером". В настоящих приложениях данных приходят из базы, а не хранятся на клиенте, поэтому нам нужно их получать и отправлять.
https://codesandbox.io/s/redux-essentials-fetch-posts-react-junior-kx3out?file=/src/App.js
В руководстве используется специальный фейковый REST API с сервером и клиентом, но я не буду так заморачиваться, сделаю простую имитацию с
Thunks
Хранилище работает синхронно, в редьюсерах не должно быть асинхронной логики. Поэтому мы выносим ее в thunks (санки).
Санки - это функции, которые имеют доступ к хранилищу (через аргументы). Они могут выполнять любые асинхронные действия и в нужный момент диспатчить что-нибудь в хранилище.
Мы работаем с санками как с экшенами, передаем их в метод
createAsyncThunk
Для создания санков используем метод createAsyncThunk. Передаем ему префикс для экшенов и функцию с логикой асинхронного запроса, которая должна возвращать промис. Под капотом
Итак, thunk creator у нас есть и экшены, связанные с ним, тоже. Но хранилище пока ничего не знает об этих экшенах и не умеет их обрабатывать. Добавляем редьюсеры для них с помощью метода
Состояние и отображение
Немного меняем состояние, теперь в нем есть поле
Список
Кроме того, в этом же компоненте с помощью селектора извлекаем текущий статус запроса. Если данные еще грузятся, выводим лоадер, чтобы пользователь знал, что происходит.
#redux #управлениесостоянием #документация #примерыкода
Теперь сделаем наше приложение более реалистичным - установим связь с "сервером". В настоящих приложениях данных приходят из базы, а не хранятся на клиенте, поэтому нам нужно их получать и отправлять.
https://codesandbox.io/s/redux-essentials-fetch-posts-react-junior-kx3out?file=/src/App.js
В руководстве используется специальный фейковый REST API с сервером и клиентом, но я не буду так заморачиваться, сделаю простую имитацию с
setTimeout
.Thunks
Хранилище работает синхронно, в редьюсерах не должно быть асинхронной логики. Поэтому мы выносим ее в thunks (санки).
Санки - это функции, которые имеют доступ к хранилищу (через аргументы). Они могут выполнять любые асинхронные действия и в нужный момент диспатчить что-нибудь в хранилище.
Мы работаем с санками как с экшенами, передаем их в метод
dispatch
, а чтобы все правильно обрабатывалось, нужно использовать миддлвар redux-thunk. createAsyncThunk
Для создания санков используем метод createAsyncThunk. Передаем ему префикс для экшенов и функцию с логикой асинхронного запроса, которая должна возвращать промис. Под капотом
createAsyncThunk
диспатчит экшен перед началом выполнения и сразу после выполнения наше функции (может быть удачный или ошибочный).Итак, thunk creator у нас есть и экшены, связанные с ним, тоже. Но хранилище пока ничего не знает об этих экшенах и не умеет их обрабатывать. Добавляем редьюсеры для них с помощью метода
extraReducers
. extraReducers
это функция, которая в качестве аргумента получает builder
. Вот в этот билдер и нужно добавить обработчики для новых экшенов (метод builder.addCase
).Состояние и отображение
Немного меняем состояние, теперь в нем есть поле
items
для хранения списка постов, а также поля status
и error
для хранения состояния запроса. Вносим изменения в селекторы, так как путь к данным изменился. Добавляем также новый селектор getStatus
.Список
items
изначально пустой, чтобы его заполнить, нужно запросить данные "с сервера". Делаем это в компоненте PostsList
- внутри хука useEffect.Кроме того, в этом же компоненте с помощью селектора извлекаем текущий статус запроса. Если данные еще грузятся, выводим лоадер, чтобы пользователь знал, что происходит.
#redux #управлениесостоянием #документация #примерыкода
CodeSandbox
Redux Essentials. Fetch posts. React Junior - CodeSandbox
Redux Essentials. Fetch posts. React Junior by furrycat.web using @reduxjs/toolkit, date-fns, react, react-dom, react-redux, react-router-dom, react-scripts, styled-components
👍1
Хорошие практики Redux
На базе предыдущего шага:
1. Инкапсуляция логики извлечения данных внутри селекторов. Структура хранилища изменилась, и если бы не было селекторов, пришлось бы вносить изменения во все компоненты, которые получают данных из хранилища.
2. Состояние запроса хранится в виде строки из перечисления (enum).
#redux #управлениесостоянием #паттерны
На базе предыдущего шага:
1. Инкапсуляция логики извлечения данных внутри селекторов. Структура хранилища изменилась, и если бы не было селекторов, пришлось бы вносить изменения во все компоненты, которые получают данных из хранилища.
2. Состояние запроса хранится в виде строки из перечисления (enum).
#redux #управлениесостоянием #паттерны
Telegram
React Junior
Статус асинхронного запроса
В документации Redux описан хороший паттерн работы с асинхронными запросами. Он не относится непосредственно к Redux, применять его можно где угодно.
Очень часто для отслеживания состояния запроса используют флаги типа isLoading…
В документации Redux описан хороший паттерн работы с асинхронными запросами. Он не относится непосредственно к Redux, применять его можно где угодно.
Очень часто для отслеживания состояния запроса используют флаги типа isLoading…
👍1
Еще раз про createAsyncThunk
Это функция для создания thunk creators. Используем, если нужны экшены начала и конца запроса.
❎ Без
Это функция для создания thunk creators. Используем, если нужны экшены начала и конца запроса.
❎ Без
createAsyncThunk
:// action creators✅ С
const getFetchPostsPending = function() {
type: 'posts/fetchPosts/pending'
};
const getFetchPostsFulfilled = function(posts) {
type: 'posts/fetchPosts/fulfilled',
payload: posts
};
const getFetchPostsRejected = function(error) {
type: 'posts/fetchPosts/rejected',
error
};
// thunk creator
const fetchPosts = function(params) {
return async function (dispatch) {
dispatch(getFetchPostsPending());
try {
const posts = await fakeApi.getPosts(params);
dispatch(getFetchPostsFulfilled(posts))
} catch (err) {
dispatch(getFetchPostsRejected(err.toString()))
}
}
}
// обработка
const postsReducer = function(state, action) {
switch(action.type) {
case 'posts/fetchPosts/pending':
// ...
case 'posts/fetchPosts/fulfilled':
// ...
case 'posts/fetchPosts/rejected':
// ...
}
}
createAsyncThunk
:// thunk creator#redux #управлениесостоянием #примерыкода
export const fetchPosts = createAsyncThunk("posts/fetchPosts", async function() {
const response = await fakeApi.getPosts();
return response.data;
});
// обработка
const postsSlice = createSlice({
// ...
extraReducers(builder) {
builder
.addCase(fetchPosts.pending, function(state, action) { })
.addCase(fetchPosts.fulfilled, function(state, action) { })
.addCase(fetchPosts.rejected, function(state, action) { });
}
})
👍1
Builder
У него есть три метода:
-
-
-
#redux #управлениесостоянием #документация
builder
позволяет добавлять в хранилище дополнительные редьюсеры - для дополнительных экшенов, которые генерируются где-то вне createSlice
.У него есть три метода:
-
builder.addCase
- для конкретного типа экшена. Первым аргументом нужно передать либо action creator, либо строку с типом экшена.-
bulder.addMatcher
- первым аргументом принимает функцию-матчер. В эту функцию передаются все экшены, редьюсер срабатывает, если матчер вернет true
.-
builder.addDefaultCase
- принимает только редьюсер, который срабатывает, если не сработал ни один другой редьюсер. #redux #управлениесостоянием #документация
👍2
Redux Essentials 9. Запрос пользователей
По аналогии с запросом статей делаем запрос пользователей.
https://codesandbox.io/s/redux-essentials-fetch-users-react-junior-ipw0r8?file=/src/App.js
1. Пишем thunk creator с помощью
2. Добавляем редьюсер для экшена
3. Диспатчим новый санк в файле
#redux #управлениесостоянием #документация #примерыкода
По аналогии с запросом статей делаем запрос пользователей.
https://codesandbox.io/s/redux-essentials-fetch-users-react-junior-ipw0r8?file=/src/App.js
1. Пишем thunk creator с помощью
createAsyncThunk
. 2. Добавляем редьюсер для экшена
fetchUsers.fulfilled
.3. Диспатчим новый санк в файле
index.js
, там где импортируем объект хранилища.#redux #управлениесостоянием #документация #примерыкода
CodeSandbox
Redux Essentials. Fetch users. React Junior - CodeSandbox
Redux Essentials. Fetch users. React Junior by furrycat.web using @reduxjs/toolkit, date-fns, react, react-dom, react-redux, react-router-dom, react-scripts, styled-components
👍1
Redux Essentials 10. Сохранение постов
Добавляем еще один thunk creator
https://codesandbox.io/s/redux-essentials-create-post-react-junior-cbfh4u?file=/src/App.js
Убираем редьюсер
Для загрузки постов мы добавили в слайс поле
Добавляем еще один thunk creator
addNewPost
(с помощью createAsyncThunk
), который будет выполнять запрос к фейковому серверу, отправлять данные из формы и получать обратно объект нового поста (с уникальным id). Создание id происходит на сервере, как это обычно и бывает в реальных приложениях.https://codesandbox.io/s/redux-essentials-create-post-react-junior-cbfh4u?file=/src/App.js
Убираем редьюсер
postAdded
и вместо него добавляем новый кейс в extraReducers
- для экшена addNewPost.fulfilled
.Для загрузки постов мы добавили в слайс поле
status
и отслеживали статус запроса, чтобы отображать лоадер. Здесь пойдем другим путем - будем отслеживать статус прямо в компоненте (подробнее - возвращение промиса из thunk). Пока идет запрос, заблокируем отправку формы.await dispatch(addNewPost({ title, content, user: userId })).unwrap()Обратите внимание на метод
unwrap()
у результата выполнения функции dispatch
. Его добавляет Redux Toolkit. Если промис завершился неудачно, этот метод выбросит ошибку, которую мы сможем поймать в try...catch
#redux #управлениесостоянием #документация #примерыкодаCodeSandbox
Redux Essentials. Create post. React Junior - CodeSandbox
Redux Essentials. Create post. React Junior by furrycat.web using @reduxjs/toolkit, date-fns, react, react-dom, react-redux, react-router-dom, react-scripts, styled-components
👍1
Redux Essentials 11. Список авторов и страница автора
На следующем этапе добавляем страницу со списком пользователей и страницу отдельного пользователя со списком статей.
https://codesandbox.io/s/redux-essentials-users-list-user-page-react-junior-xmtqds?file=/src/App.js
Ничего нового:
1) Новый селектор
3) Новый компонент UserPage (использует хук
4) Новые роуты
5) Ссылка на страницу авторов в шапке сайта + ссылки на авторов в превью статей и на странице статьи
#redux #управлениесостоянием #документация #примерыкода
На следующем этапе добавляем страницу со списком пользователей и страницу отдельного пользователя со списком статей.
https://codesandbox.io/s/redux-essentials-users-list-user-page-react-junior-xmtqds?file=/src/App.js
Ничего нового:
1) Новый селектор
getUserPosts
в postsSlice
2) Новый компонент UsersList (использует селектор getUsers
)3) Новый компонент UserPage (использует хук
useParams
и селектор getUserPosts
)4) Новые роуты
/users
и /users/:userId
в App.js5) Ссылка на страницу авторов в шапке сайта + ссылки на авторов в превью статей и на странице статьи
#redux #управлениесостоянием #документация #примерыкода
CodeSandbox
Redux Essentials. Users list & User page. React Junior - CodeSandbox
Redux Essentials. Users list & User page. React Junior by furrycat.web using @reduxjs/toolkit, date-fns, react, react-dom, react-redux, react-router-dom, react-scripts, styled-components
👍1