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
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