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
Forwarded from Cat in Web
React 18
Перевод оригинальной статьи на Хабре: https://habr.com/ru/post/659537/
Обзор новинок последнего релиза - а их немало.
Конкурентный рендеринг
Кардинально изменилась модель рендеринга, появилась конкурентность - нечто подкапотное, что позволяет подготавливать несколько версий интерфейса одновременно. Рендеринг теперь может прерываться, откладываться (раньше был синхронным). Благодаря этому основной поток не блокируется и приложение может реагировать на действия пользователя, даже если за кулисами рендерится что-то огромное.
Появилось несколько новых хуков для работы с новым функционалом, однако в перспективе команда React ожидает, что они будут использоваться в основном для интеграции библиотек с поддержкой конкурентности, а не напрямую. Например, библиотекой маршрутизации для перехода между страницами.
Автоматическое пакетирование
Или группировка нескольких обновлений в один рендеринг. Раньше пакетировались только обновления внутри обработчиков событий React, теперь пакетируются еще и обновления внутри промисов, таймеров, нативных обработчиков и пр.
Переходы (transitions)
Обновления теперь делятся на срочные (немедленная реакция на действие пользователя, например, ввод текста) и переходные (не срочные). Последние - это переход интерфейса из одного состояния в другое (например, появление списка результатов после применения фильтров).
Новая функция
Suspense
Расширились возможности React.Suspense. Раньше он только позволял лениво загружать код с помощью React.lazy и не поддерживался при серверном рендеринге. Теперь работает и на сервере тоже и хорошо сочетается с API переходов.
Новые API рендеринга
Новые методы для рендеринга -
Двойное монтирование компонентов
В строгом режиме в dev mode добавлена проверка на "устойчивость к многократному монтированию" - компоненты в первый раз монтируются, сразу размонтируются с сохранением состояния и монтируются снова. Это нужно для будущих улучшений.
Новые хуки
-
-
-
-
-
#react
Перевод оригинальной статьи на Хабре: https://habr.com/ru/post/659537/
Обзор новинок последнего релиза - а их немало.
Конкурентный рендеринг
Кардинально изменилась модель рендеринга, появилась конкурентность - нечто подкапотное, что позволяет подготавливать несколько версий интерфейса одновременно. Рендеринг теперь может прерываться, откладываться (раньше был синхронным). Благодаря этому основной поток не блокируется и приложение может реагировать на действия пользователя, даже если за кулисами рендерится что-то огромное.
Появилось несколько новых хуков для работы с новым функционалом, однако в перспективе команда React ожидает, что они будут использоваться в основном для интеграции библиотек с поддержкой конкурентности, а не напрямую. Например, библиотекой маршрутизации для перехода между страницами.
Автоматическое пакетирование
Или группировка нескольких обновлений в один рендеринг. Раньше пакетировались только обновления внутри обработчиков событий React, теперь пакетируются еще и обновления внутри промисов, таймеров, нативных обработчиков и пр.
Переходы (transitions)
Обновления теперь делятся на срочные (немедленная реакция на действие пользователя, например, ввод текста) и переходные (не срочные). Последние - это переход интерфейса из одного состояния в другое (например, появление списка результатов после применения фильтров).
Новая функция
startTransition
(или хук useTransition
) позволяет явно указать "не срочные" обновления. Их выполнение может быть прервано, если в процессе поступят какие-то "срочные" обновления. Suspense
Расширились возможности React.Suspense. Раньше он только позволял лениво загружать код с помощью React.lazy и не поддерживался при серверном рендеринге. Теперь работает и на сервере тоже и хорошо сочетается с API переходов.
Новые API рендеринга
Новые методы для рендеринга -
createRoot
и hydrateRoot`на клиенте, `renderToPipeableStream
и renderToReadableStream
на сервере.Двойное монтирование компонентов
В строгом режиме в dev mode добавлена проверка на "устойчивость к многократному монтированию" - компоненты в первый раз монтируются, сразу размонтируются с сохранением состояния и монтируются снова. Это нужно для будущих улучшений.
Новые хуки
-
useId
- генерация уникальных идентификаторов-
useTransition
- позволяет пометить обновления как "переходные" (см. выше)-
useDeferredValue
- откладывает не срочный перерендеринг-
useSyncExternalStore
- хук для библиотек, работающих с внешним состоянием-
useInsertionEffect
- хук для библиотек CSS-in-JS для инъекции стилей, срабатывает до layout effect.#react
Хабр
React 18
В нашем последнем посте мы поделились пошаговыми инструкциями по обновлению вашего приложения до React 18 . В текущем посте мы дадим обзор того, что нового появилось в React 18, и что это означает для...
👍1
Что мне не нравится в react-router
Статья (рус.): https://habr.com/ru/post/599347/
Мнение разработчика о недостатках React Router. Местами субъективно (точка зрения относительно больших сложных проектов), но в любом случае интересно и полезно для ознакомления. Претензии в основном к старой версии библиотеки, в последнем релизе появилось много полезных фич.
Главные претензии:
1. JSX плохо подходит для описания конфига роутинга. Удобнее работать с обычным JSON.
2. Отсутствие модульности, сложности с формированием сложных ссылок "от корня".
3. Лишние перерендеры одинаковых компонентов в разных роутах.
В комментариях тоже интересно.
#роутинг #ссылки
Статья (рус.): https://habr.com/ru/post/599347/
Мнение разработчика о недостатках React Router. Местами субъективно (точка зрения относительно больших сложных проектов), но в любом случае интересно и полезно для ознакомления. Претензии в основном к старой версии библиотеки, в последнем релизе появилось много полезных фич.
Главные претензии:
1. JSX плохо подходит для описания конфига роутинга. Удобнее работать с обычным JSON.
2. Отсутствие модульности, сложности с формированием сложных ссылок "от корня".
3. Лишние перерендеры одинаковых компонентов в разных роутах.
В комментариях тоже интересно.
#роутинг #ссылки
Хабр
Что мне не нравится в react-router
Недавно меня спросили: “Зачем я отказался от библиотеки react-router и перешел на свой велосипед?” Честно говоря, вопросы, связанные с моим вариантом роутинга, мне задавали уже раз пять. Последний раз...
👍1
Redux Essentials 12. Уведомления
Добавляем функционал уведомлений - страницу со списком и возможность обновить список (получить "новые" уведомления), нажав на кнопку.
https://codesandbox.io/s/redux-essentials-notifications-react-junior-qmk9tf
Так как это просто демка Redux, уведомления будут довольно куцые.
API
В фейковый апи добавлен метод для генерации рандомных сообщений. Он получает время последнего сообщения и создает несколько "новых" сообщений.
Слайс
Добавляем новую фичу
Этот фрагмент состояния представляет собой простой массив уведомлений, никакие статусы тут отслеживаться не будут.
Экшен всего один -
Есть два селектора -
Thunk
Добавляем также thunk creator
Из интересного - функция принимает два параметра - первый пользовательский, если в thunk нужно передать какие-то данные, второй -
Нужно также добавить редьюсер для экшена
Список
Добавляем компонент
Кроме того, добавляем в
#redux #управлениесостоянием #документация #примерыкода
Добавляем функционал уведомлений - страницу со списком и возможность обновить список (получить "новые" уведомления), нажав на кнопку.
https://codesandbox.io/s/redux-essentials-notifications-react-junior-qmk9tf
Так как это просто демка Redux, уведомления будут довольно куцые.
API
В фейковый апи добавлен метод для генерации рандомных сообщений. Он получает время последнего сообщения и создает несколько "новых" сообщений.
Слайс
Добавляем новую фичу
features/notifications
и создаем новый слайс, который нужно будет добавить в метод configureStore
в app/store.js
.Этот фрагмент состояния представляет собой простой массив уведомлений, никакие статусы тут отслеживаться не будут.
Экшен всего один -
allNotificationsRead
. У каждого уведомления будет статус "прочитано/не прочитано", чтобы можно было подсвечивать новые. Этот экшен будет помечать все обновления прочитанными.Есть два селектора -
getNotifications
и getUnreadNotificationsCount
.Thunk
Добавляем также thunk creator
fetchNotifications
, который будет обращаться к "серверу" и получать новые уведомления.Из интересного - функция принимает два параметра - первый пользовательский, если в thunk нужно передать какие-то данные, второй -
thunkAPI
- объект с методами для работы с хранилищем (getStore
, dispatch
).Нужно также добавить редьюсер для экшена
fetchNotifications.fulfilled
в секцию extraReducers
. Раньше мы всегда оформляли ее как функцию и добавляли все обработчики через объект builder
. Но тут используется другой синтаксис - объект, поля которого представляют собой имена экшенов. Так тоже можно.extraReducers: {Выглядит более понятно, чем вариант с функцией, но тот обычно удобнее.
[fetchNotifications.fulfilled]: function(state, action) {}
}
Список
Добавляем компонент
NotificationsList
, который будет рендерить список уведомлений, а также помечать все уведомления прочитанными. Для этого используем хук useLayoutEffect.Кроме того, добавляем в
App.js
новый роут notifications
, а в шапку - новую ссылку. Плюс в шапке еще появилась кнопка для обновления списка (получения новых уведомлений). Если ее нажать, появится количество непрочитанных сообщений, которое обнулится при переходе на страницу списка.#redux #управлениесостоянием #документация #примерыкода
CodeSandbox
Redux Essentials. Notifications. React Junior - CodeSandbox
Redux Essentials. Notifications. React Junior by furrycat.web using @reduxjs/toolkit, date-fns, react, react-dom, react-redux, react-router-dom, react-scripts, styled-components
Redux Essentials 13. Мемоизация селекторов
В текущей версии проекта (https://qmk9tf.csb.app/users/1) перейдем на страницу пользователя, откроем в панели разработчика вкладку Profiler (из React DevTools) и нажмем на кнопку записи.
Теперь обновим список уведомлений (кнопка в шапке) и после этого остановим запись.
Увидим, что помимо шапки (в которой появилось кол-во непрочитанных сообщений), перерендерилась еще и страница
Впрочем, мы уже знаем, в чем дело - в селекторе
Чтобы решить проблему, используем метод createSelector (из библиотеки reselect, берем из пакета @reduxjs/toolkit).
У него будут два входных селектора - уже существующий
Обновленный код проекта: https://codesandbox.io/s/redux-essentials-memoized-selectors-react-junior-e8u8e6?file=/src/features/posts/postsSlice.js
Сам проект: https://e8u8e6.csb.app/users/1
#redux #управлениесостоянием #документация #примерыкода
В текущей версии проекта (https://qmk9tf.csb.app/users/1) перейдем на страницу пользователя, откроем в панели разработчика вкладку Profiler (из React DevTools) и нажмем на кнопку записи.
Теперь обновим список уведомлений (кнопка в шапке) и после этого остановим запись.
Увидим, что помимо шапки (в которой появилось кол-во непрочитанных сообщений), перерендерилась еще и страница
UserPage
. Казалось бы, с чего это вдруг, в этом компоненте изменений не было. Впрочем, мы уже знаем, в чем дело - в селекторе
getUserPosts
, который возвращает новый массив, так как используем метод filter
.Чтобы решить проблему, используем метод createSelector (из библиотеки reselect, берем из пакета @reduxjs/toolkit).
У него будут два входных селектора - уже существующий
getPosts
, который возвращает массив всех статей, и еще один, который возвращает только id пользователя. Выходной селектор уже фильтрует полученный массив. Таким образом, если общий список не изменится, перерендера не будет.Обновленный код проекта: https://codesandbox.io/s/redux-essentials-memoized-selectors-react-junior-e8u8e6?file=/src/features/posts/postsSlice.js
Сам проект: https://e8u8e6.csb.app/users/1
#redux #управлениесостоянием #документация #примерыкода
👍1
Redux Essentials 14. Мемоизация компонентов
Еще одна проблема производительности в текущей версии проекта (https://qmk9tf.csb.app/).
Если на главной странице (со списком постов) поставить реакцию под одной из статей, то перерендерятся ВСЕ статьи, а не только та, которая изменилась.
Дело в том, что при изменении одного объекта статьи меняется весь массив статей. Из-за этого перерендеривается весь компонент
Есть несколько способов решить эту проблему.
Первый - обернуть компонент
Обновленный код проекта: https://codesandbox.io/s/redux-essentials-memoized-selectors-react-junior-e8u8e6?file=/src/features/posts/PostsList.js
Сам проект: https://e8u8e6.csb.app/
Второй - переписать селектор
Третий - переделать состояние в целом, чтобы в нем хранился массив айдишников, который изменяется только при изменении набора постов. Другими словами, нормализовать состояние. Этим займемся в следующий раз.
#redux #управлениесостоянием #документация #примерыкода
Еще одна проблема производительности в текущей версии проекта (https://qmk9tf.csb.app/).
Если на главной странице (со списком постов) поставить реакцию под одной из статей, то перерендерятся ВСЕ статьи, а не только та, которая изменилась.
Дело в том, что при изменении одного объекта статьи меняется весь массив статей. Из-за этого перерендеривается весь компонент
PostsList
, а с ним и все его потомки.Есть несколько способов решить эту проблему.
Первый - обернуть компонент
PostExcerpt
в React.memo
. Тогда он не будет перерендериваться при перерендере родителя (если у него не поменяются пропсы).Обновленный код проекта: https://codesandbox.io/s/redux-essentials-memoized-selectors-react-junior-e8u8e6?file=/src/features/posts/PostsList.js
Сам проект: https://e8u8e6.csb.app/
Второй - переписать селектор
getPosts
, чтобы он возвращал только айдишники статей, и мемоизировать его с помощью shallowEqual. А в компоненте PostExcerpt
получать только id
и по нему находить нужный пост.Третий - переделать состояние в целом, чтобы в нем хранился массив айдишников, который изменяется только при изменении набора постов. Другими словами, нормализовать состояние. Этим займемся в следующий раз.
#redux #управлениесостоянием #документация #примерыкода
👍1
Плохие привычки Middle React разработчиков
Статья (англ.): https://dev.to/srmagura/bad-habits-of-mid-level-react-developers-b41
Автор статьи перечисляет частые ошибки и плохие практики, которые видит, делая ревью чужого кода. В комментариях согласны не со всем :)
Итак, React-разработчики часто:
👎 Дублируют состояние
Плохо выглядит и может привести к рассинхрону.
👎 Не используют редьюсеры
Для работы с более-менее сложным состоянием редьюсеры (useReducer, redux) предпочтительнее простого useState. В частности, автор рекомендует работать через редьюсер с любым массивом, который можно редактировать.
👎 Не пишут юнит-тесты
Речь в статье идет о тестах, написание которых не занимает много времени, но приносит большую пользу, например, о тестах для редьюсеров.
👎 Недостаточно используют React.memo, useMemo и useCallback
Что приводит к проблемам с производительностью.
👎 Неправильно используют useEffect
Эффект запускается либо слишком часто, либо недостаточно часто. Из полезного: автор рекомендует помещать функции, которые задействованы в эффекте в useRef, чтобы сохранять их идентичность.
👎 Забывают про юзабилити
Не связано напрямую с React и вообще много где встречается.
👎 Не стремятся к совершенствованию знаний в CSS и веб-дизайне
Добавка к предыдущему пункту.
В заключение автор дает несколько советов-"хороших практик":
👍 Использовать исключительно TypeScript
👍 Использовать библиотеку для запросов (data-fetching)
👍 Использовать серверный рендеринг, только если он вам действительно нужен
👍 Использовать модульный CSS и связывать стили с компонентами
#ссылки #паттерны
Статья (англ.): https://dev.to/srmagura/bad-habits-of-mid-level-react-developers-b41
Автор статьи перечисляет частые ошибки и плохие практики, которые видит, делая ревью чужого кода. В комментариях согласны не со всем :)
Итак, React-разработчики часто:
👎 Дублируют состояние
Плохо выглядит и может привести к рассинхрону.
👎 Не используют редьюсеры
Для работы с более-менее сложным состоянием редьюсеры (useReducer, redux) предпочтительнее простого useState. В частности, автор рекомендует работать через редьюсер с любым массивом, который можно редактировать.
👎 Не пишут юнит-тесты
Речь в статье идет о тестах, написание которых не занимает много времени, но приносит большую пользу, например, о тестах для редьюсеров.
👎 Недостаточно используют React.memo, useMemo и useCallback
Что приводит к проблемам с производительностью.
👎 Неправильно используют useEffect
Эффект запускается либо слишком часто, либо недостаточно часто. Из полезного: автор рекомендует помещать функции, которые задействованы в эффекте в useRef, чтобы сохранять их идентичность.
👎 Забывают про юзабилити
Не связано напрямую с React и вообще много где встречается.
👎 Не стремятся к совершенствованию знаний в CSS и веб-дизайне
Добавка к предыдущему пункту.
В заключение автор дает несколько советов-"хороших практик":
👍 Использовать исключительно TypeScript
👍 Использовать библиотеку для запросов (data-fetching)
👍 Использовать серверный рендеринг, только если он вам действительно нужен
👍 Использовать модульный CSS и связывать стили с компонентами
#ссылки #паттерны
DEV Community
Bad Habits of Mid-Level React Developers
If you're a mid-level React developer looking to become an advanced React developer, this post is for...
👍3❤1
Redux Essentials 15. Нормализация состояния
Преимущества хранения состояния в нормализованном виде мы уже обсуждали. Помимо прочего это еще и улучшает производительность. Список элементов представлен в виде массива их идентификаторов, поэтому если состояние одного из элементов меняется, на сам список это не влияет.
https://codesandbox.io/s/redux-essentials-normalized-state-react-junior-q2x3te?file=/src/App.js
Для создания нормализованного состояния и управления им используется метод createEntityAdapter.
PostsSlice
Создаем адаптер
Для получения начального состояния - метод
Теперь нужно внести изменения в редьюсеры и селекторы. Данные постов теперь хранятся в
Компоненты
Изменилась концепция получения данных в компонентах. Компонент
Таким образом, компонент
Теперь можно повторить эксперимент. Открываем проект (https://q2x3te.csb.app/), включаем запись, ставим лайк одному из постов, и видим, что перерендерился только он.
Пользователи и уведомления
По аналогии вносим изменения в
#redux #управлениесостоянием #документация #примерыкода
Преимущества хранения состояния в нормализованном виде мы уже обсуждали. Помимо прочего это еще и улучшает производительность. Список элементов представлен в виде массива их идентификаторов, поэтому если состояние одного из элементов меняется, на сам список это не влияет.
https://codesandbox.io/s/redux-essentials-normalized-state-react-junior-q2x3te?file=/src/App.js
Для создания нормализованного состояния и управления им используется метод createEntityAdapter.
PostsSlice
Создаем адаптер
postsAdapter
. Метод createEntityAdapter
может принимать ряд настроек, например, sortComparer
- функцию для сортировки массива. Сейчас у нас сортировка (по дате) происходит прямо в компоненте PostsList.Для получения начального состояния - метод
getInitialState
.Теперь нужно внести изменения в редьюсеры и селекторы. Данные постов теперь хранятся в
state.entities
(объект), а все операции совершаются через методы адаптера.Компоненты
Изменилась концепция получения данных в компонентах. Компонент
PostsList
теперь должен получать только список идентификаторов, это защитит нас от перерендеринга при изменении отдельных статей.Таким образом, компонент
PostExcerpt
теперь должен самостоятельно получать данные статьи, чтобы отобразить их.Теперь можно повторить эксперимент. Открываем проект (https://q2x3te.csb.app/), включаем запись, ставим лайк одному из постов, и видим, что перерендерился только он.
Пользователи и уведомления
По аналогии вносим изменения в
features/users
и features/notifications
: создаем адаптеры, изменяем редьюсеры и селекторы.#redux #управлениесостоянием #документация #примерыкода
Telegram
React Junior
Нормализация состояния
Во всех предыдущих примерах элементы хранились в store в виде массива. Но в больших проектах со сложным состоянием разумно использовать другую структуру данных - словарь с доступом по идентификатору (обычный JavaScript-объект).
Это…
Во всех предыдущих примерах элементы хранились в store в виде массива. Но в больших проектах со сложным состоянием разумно использовать другую структуру данных - словарь с доступом по идентификатору (обычный JavaScript-объект).
Это…
👍3
Композиция компонентов в React: как правильно?
Статья (англ.): https://www.developerway.com/posts/components-composition-how-to-get-it-right
Секрет создания масштабируемых приложений на React - это извлечение "правильных" компонентов в правильное время. Хороший компонент - это понятный компонент, который не делает ничего лишнего.
Хороший компонент обычно можно описать короткой фразой в духе
"компонент, который что-то реализует" или "компонент, который объединяет несколько компонентов". Старайтесь не смешивать эти сущности.
Компоненты
Автор выделяет два основных типа компонентов: "простые" компоненты и "компоненты-контейнеры". Основное различие между ними в том, что компоненты-контейнеры используют проп
Принципы разработки
Основные принципы, которых автор советует придерживаться, чтобы из чтобы избежать "переусложнения" кода:
- всегда начинайте реализацию "сверху"
- извлекайте компоненты только при реальной необходимости
- начинайте с "простых" компонентов, используйте техники композиции только при реальной необходимости
Когда наступает подходящий момент для выделения отдельных компонентов?
- если компонент слишком большой, так что его неудобно читать.
- если компонент занимается "не своим делом", содержит состояние, которое к нему не относится. В статье приведен хороший пример с кнопкой, клик по которой открывает модальное окно.
Контейнерные компоненты
Извлекайте "контейнерные компоненты", если появляется необходимость переиспользовать какую-то логику (визуал или поведение) для элементов, которые должны оставаться под контролем пользователя. То есть если эта логика не связана с элементами напрямую, например, сворачивающиеся секции меню.
Кроме того, "контейнеры" - это прекрасное решение проблем с производительностью, так как Компоненты, вставленные через props.children, не обновляются при рендере родительского компонента.
#ссылки #компоненты #паттерны
Статья (англ.): https://www.developerway.com/posts/components-composition-how-to-get-it-right
Секрет создания масштабируемых приложений на React - это извлечение "правильных" компонентов в правильное время. Хороший компонент - это понятный компонент, который не делает ничего лишнего.
Хороший компонент обычно можно описать короткой фразой в духе
"компонент, который что-то реализует" или "компонент, который объединяет несколько компонентов". Старайтесь не смешивать эти сущности.
Компоненты
Автор выделяет два основных типа компонентов: "простые" компоненты и "компоненты-контейнеры". Основное различие между ними в том, что компоненты-контейнеры используют проп
children
, то есть в них может быть вложен совершенно посторонний код. Принципы разработки
Основные принципы, которых автор советует придерживаться, чтобы из чтобы избежать "переусложнения" кода:
- всегда начинайте реализацию "сверху"
- извлекайте компоненты только при реальной необходимости
- начинайте с "простых" компонентов, используйте техники композиции только при реальной необходимости
Когда наступает подходящий момент для выделения отдельных компонентов?
- если компонент слишком большой, так что его неудобно читать.
- если компонент занимается "не своим делом", содержит состояние, которое к нему не относится. В статье приведен хороший пример с кнопкой, клик по которой открывает модальное окно.
Контейнерные компоненты
Извлекайте "контейнерные компоненты", если появляется необходимость переиспользовать какую-то логику (визуал или поведение) для элементов, которые должны оставаться под контролем пользователя. То есть если эта логика не связана с элементами напрямую, например, сворачивающиеся секции меню.
Кроме того, "контейнеры" - это прекрасное решение проблем с производительностью, так как Компоненты, вставленные через props.children, не обновляются при рендере родительского компонента.
#ссылки #компоненты #паттерны
Developerway
React components composition: how to get it right
What is components composition? How do you know when to start splitting a big component into smaller pieces and how to compose them properly? What makes a good component?
👍3
Redux Essentials 16. RTK Query. Создание слайса
RTK Query - это еще один уровень абстракции над абстракциями Redux, позволяющий инкапсулировать работу с API: методы получения/обновления/удаления данных, состояние выполнения запроса, синхронизация состояния на клиенте и на сервере, оптимистичные обновления клиентского стейта, кеширование и т.д.
При этом все, что связано с API, выносится в отдельный слайс. Если у нас есть в приложении несколько разных запросов к одному и тому же серверу (работа со статьями, уведомлениями) - все это будет в отдельном слайсе, и методы, и сами данные.
RTK Query предоставляет две основные функции:
-
-
Они находятся в пакете
Есть еще
Проект: https://codesandbox.io/s/redux-essentials-rtk-query-react-junior-lced2j?file=/src/features/api/apiSlice.js
Создание и добавление слайса
Слайс для API создаем в файле
Важно правильно подключить новый слайс в методе
Сам сгенерированный редьюсер находится в
Кроме того, нужно добавить миддлвар
#redux #rtkquery #обменданными #управлениесостоянием #документация #примерыкода
RTK Query - это еще один уровень абстракции над абстракциями Redux, позволяющий инкапсулировать работу с API: методы получения/обновления/удаления данных, состояние выполнения запроса, синхронизация состояния на клиенте и на сервере, оптимистичные обновления клиентского стейта, кеширование и т.д.
При этом все, что связано с API, выносится в отдельный слайс. Если у нас есть в приложении несколько разных запросов к одному и тому же серверу (работа со статьями, уведомлениями) - все это будет в отдельном слайсе, и методы, и сами данные.
RTK Query предоставляет две основные функции:
-
createApi
для создания слайса;-
fetchBaseQuery
- небольшая утилитарная обертка вокруг метода fetch
Они находятся в пакете
@reduxjs/toolkit/query
- это базовая версия библиотеки.Есть еще
@reduxjs/toolkit/query/react
- те же самые функции специально для React. Они автоматически генерируют хуки на базе созданных методов. Мы будем использовать именно этот пакет.Проект: https://codesandbox.io/s/redux-essentials-rtk-query-react-junior-lced2j?file=/src/features/api/apiSlice.js
Создание и добавление слайса
Слайс для API создаем в файле
features/api/apiSlice.js
. export const apiSlice = createApi({Помимо прочих настроек метод
reducerPath: 'api',
// ...
})
createApi
принимает поле reducerPath
, в котором нужно указать, где именно в общем state
будут лежать данные, полученные из API. По умолчанию значение этого поля api
- то есть данные нужно будет извлекать из state.api
.Важно правильно подключить новый слайс в методе
configureStore
. Чтобы не ошибиться, используем в качестве названия поля свойство apiSlice.reducerPath
.Сам сгенерированный редьюсер находится в
apiSlice.reducer
.Кроме того, нужно добавить миддлвар
apiSlice.middlewar
для кеширования данных. Сделать это можно в методе configureStore
в настройке middleware
. Она принимает функцию, которой в качестве аргумента передается метод getDefaultMiddleware
. Вернуть нужно обновленный массив миддлваров, поэтому вызываем этот метод и добавляем в него новый миддлвар.#redux #rtkquery #обменданными #управлениесостоянием #документация #примерыкода
👍4
Redux Essentials 16. RTK Query. Выполнение запросов
Проект: https://codesandbox.io/s/redux-essentials-rtk-query-react-junior-lced2j?file=/src/features/api/apiSlice.js
baseQuery
Основная (обязательная) настройка в методе
В качестве такой функции можно использовать встроенную
Внутри одного API-слайса предполагается, что все запросы осуществляются к одному серверу (это необязательно). Так что здесь можно установить базовые настройки запроса, например,
Так как в моем проекте реального API нет, придется использовать кастомную функцию
Вместо этого можно, например, реализовать запросы с помощью библиотеки axios.
#redux #rtkquery #обменданными #управлениесостоянием #документация #примерыкода
Проект: https://codesandbox.io/s/redux-essentials-rtk-query-react-junior-lced2j?file=/src/features/api/apiSlice.js
baseQuery
Основная (обязательная) настройка в методе
createApi
- это baseQuery
. Это функция, которая непосредственно выполняет запросы. В качестве такой функции можно использовать встроенную
fetchBaseQuery
- обертку над стандартным методом fetch
.Внутри одного API-слайса предполагается, что все запросы осуществляются к одному серверу (это необязательно). Так что здесь можно установить базовые настройки запроса, например,
baseUrl
- фрагмент урла, с которого начинаются все эндпоинты.const apiSlice = createApi({Но можно использовать и собственную функцию для выполнения запросов. Важно, чтобы она возвращала ответ в нужном формате. Полученные данные должны находиться в поле
// ...
baseQuery: fetchBaseQuery({ baseUrl: '/fakeApi' })
})
data
, а ошибка, если она есть, в поле error
. Так как в моем проекте реального API нет, придется использовать кастомную функцию
customFetchBaseQuery
, которая вместо настоящих запросов просто обращается к модулю fakeApi
.Вместо этого можно, например, реализовать запросы с помощью библиотеки axios.
#redux #rtkquery #обменданными #управлениесостоянием #документация #примерыкода
CodeSandbox
Redux Essentials. RTK Query. React Junior - CodeSandbox
Redux Essentials. RTK Query. React Junior by furrycat.web using @reduxjs/toolkit, date-fns, react, react-dom, react-redux, react-router-dom, react-scripts, styled-components
👍2
Redux Essentials 16. RTK Query. Эндпоинты
Проект: https://codesandbox.io/s/redux-essentials-rtk-query-react-junior-lced2j?file=/src/features/api/apiSlice.js
Теперь самое интересное - добавление эндпоинтов для реальной работы с данными.
Поле
У билдера есть метод
-
-
Начнем с добавления эндпоинта
Проект: https://codesandbox.io/s/redux-essentials-rtk-query-react-junior-lced2j?file=/src/features/api/apiSlice.js
Теперь самое интересное - добавление эндпоинтов для реальной работы с данными.
Поле
endpoints
в настройках метода createApi
- это функция, которая в качестве аргумента принимает builder
, а вернуть должна коллекцию (объект) эндпоинтов. У билдера есть метод
query
, который принимает объект настроек запроса. Настроек очень много, но можно пока обойтись основными:-
query
- функция, которая возвращает урл запроса. Этот урл будет присоединен к baseUrl
, если он был указан ранее.-
transformResponse
- функция для обработки ответа, если он не соответствует ожидаемому формату.Начнем с добавления эндпоинта
getPosts
для получения списка постов.const apiSlice = createApi({#redux #rtkquery #обменданными #управлениесостоянием #документация #примерыкода
// ...
endpoints: function(builder) {
return {
getPosts: builder.query({
query: function() { return "/posts" },
transformResponse: function(response) { return response.data }
})
}
}
})
CodeSandbox
Redux Essentials. RTK Query. React Junior - CodeSandbox
Redux Essentials. RTK Query. React Junior by furrycat.web using @reduxjs/toolkit, date-fns, react, react-dom, react-redux, react-router-dom, react-scripts, styled-components
👍2