Упрощенный код хранилища Redux
1. В функцию создания хранилища
2. После создания вызывается инициализирующий экшен
#управлениесостоянием #redux #примерыкода #документация
function createStore(reducer, preloadedState) {
let state = preloadedState
const listeners = []
function getState() {
return state
}
function subscribe(listener) {
listeners.push(listener)
return function unsubscribe() {
const index = listeners.indexOf(listener)
listeners.splice(index, 1)
}
}
function dispatch(action) {
state = reducer(state, action)
listeners.forEach(listener => listener())
}
dispatch({ type: '@@redux/INIT' })
return { dispatch, subscribe, getState }
}
1. В функцию создания хранилища
createStore
можно передать исходное состояние - параметр preloadedState
2. После создания вызывается инициализирующий экшен
#управлениесостоянием #redux #примерыкода #документация
Создаем свой React с рендером и useState за 30 минут
Пишем собственную реализацию React, чтобы понять, что там под капотом.
Статья (рус.): https://habr.com/ru/post/652487/
Спойлер: React будет урезанный, только рендер и хук useState, без виртуального DOM и согласования изменений
1. Настройка проекта с использованием parcel и typescript для компиляции JSX.
2. Реализация
3. Реализация метода для ререндера.
4. Реализация
В итоге получается нечто, что примерно соотствествует формуле React: интерфейс - это функция от состояния. Но без всяких оптимизаций.
Почитать интересно, чтобы еще раз это в голове уложить.
#ссылки #подкапотом
Пишем собственную реализацию React, чтобы понять, что там под капотом.
Статья (рус.): https://habr.com/ru/post/652487/
Спойлер: React будет урезанный, только рендер и хук useState, без виртуального DOM и согласования изменений
1. Настройка проекта с использованием parcel и typescript для компиляции JSX.
2. Реализация
React.createElement
и ReactDOM.render
для создания HTML-разметки из JSX.3. Реализация метода для ререндера.
4. Реализация
useState
с сохранением состояния между рендерами.В итоге получается нечто, что примерно соотствествует формуле React: интерфейс - это функция от состояния. Но без всяких оптимизаций.
Почитать интересно, чтобы еще раз это в голове уложить.
#ссылки #подкапотом
Road Map ReactJS-разработчика в 2022 году
Статья (англ.): https://medium.com/javarevisited/the-2019-react-js-developer-roadmap-9a8e290b8a56
В статье много ссылок на разные курсы (на англ.), но главное, она помогает создать общее впечатление об экосистеме и понять, куда двигаться.
Плюс, тут есть несколько ссылок на статьи с подборками источников знаний:
🔸 6 Best Websites to Learn React.js Coding for FREE in 2022
🔸 6 Best React.js Books for Beginners and Experienced Web Developers
🔸 Top 10 Online Courses to Learn React.js in Depth — Best of Lot
Итак, что должен изучить хороший React-разработчик?
✔️ 1. Основы (HTML, CSS, JS)
Без базовых знаний, понятно, никуда.
✔️ 2. Базовые скиллы разработчика
Тут и инструменты: Git, HTTP(S)-протокол со всеми основными методами (GET, POST, ...), работа с терминалом.
и теория: алгоритмы, структуры данных, шаблоны проектирования.
Действительно, в React (да и в любом инструменте в принципе) проще разобраться, когда ты понимаешь, что происходит.
✔️ 3. React JS
Ну, конечно, нельзя стать React-разработчиком, не изучив React JS.
✔️ 4. Инструменты сборки
React - современный инструмент, который использует под капотом много технологий, поэтому необходимо особым образом организовывать свои проекты, чтобы они работали в реальных условиях, например, в браузере. Для этого нужно знать, что такое менеджеры пакетов (npm, yarn, ...) и сборщики (webpack, parcel, rollup, gulp...).
✔️ 5. Стилизация
React поддерживает множество подходов к стилизации компонентов (это мы уже проходили https://yangx.top/react_junior/142), и нужно иметь о них представление. Но автор статьи советует начать с Bootstrap.
✔️ 6. Управление состоянием
Состояние - важная концепция в React, поэтому его изучаем отдельно (да, мы так и делаем). В списке технологий: контекст, redux с кучей доп. пакетов), mobx, ...
✔️ 7. Проверка типов
Нужна, чтобы избежать многочисленных ошибок. Речь, прежде всего, о TypeScript.
✔️ 8. Обработка форм
Грамотная работа с формами - очень важная часть разработки, к счастью, у нас есть множество инструментов для этого (redux form, formik, formsy, final form).
✔️ 9. Маршрутизация
Необходима для создания API. Обеспечивается React Router https://yangx.top/react_junior/230.
✔️ 10. Клиенты API
Клиентские приложения чаще всего не изолированы от внешнего мира и работают в связке с сервером, поэтому нам нужны инструменты для обеспечения этой связки (от fetch до graphql).
✔️ 11. Вспомогательные библиотеки
Инструменты, которые берут на себя отдельные задачи и облегчают жизнь разработчика. В списке: Lodash, Moment, Classnames, ...
✔️ 12. Тестирование
Все знают, что тестирование очень важно. И у нас тут огромное количество инструментов для разных видов тестирования.
✔️ 13. Интернационализация
Очень комплексная задача, для решения которой тоже есть готовые инструменты (react intl, react i18next)
✔️ 14. SSR
Первым в списке идет Next.js, и автор считает, что этого достаточно (по крайней мере, для начала)
✔️ 15. Генераторы статических сайтов
Тут только Gatsby.js
✔️ 16. Интеграция с бэкенд-фреймворками
Например, React on Rails для интеграции с Rails.
✔️ 17. Мобильная разработка
React может работать не только в вебе. Для мобильной разработки предлагается React Native.
✔️ 18. Разработка для Desktop
Для десктопной разработки тоже есть решения: Proton Native, Electron, React Native Windows.
✔️ 19. Виртуальная реальность
Тут React 360.
#ссылки #инструменты
Статья (англ.): https://medium.com/javarevisited/the-2019-react-js-developer-roadmap-9a8e290b8a56
В статье много ссылок на разные курсы (на англ.), но главное, она помогает создать общее впечатление об экосистеме и понять, куда двигаться.
Плюс, тут есть несколько ссылок на статьи с подборками источников знаний:
🔸 6 Best Websites to Learn React.js Coding for FREE in 2022
🔸 6 Best React.js Books for Beginners and Experienced Web Developers
🔸 Top 10 Online Courses to Learn React.js in Depth — Best of Lot
Итак, что должен изучить хороший React-разработчик?
✔️ 1. Основы (HTML, CSS, JS)
Без базовых знаний, понятно, никуда.
✔️ 2. Базовые скиллы разработчика
Тут и инструменты: Git, HTTP(S)-протокол со всеми основными методами (GET, POST, ...), работа с терминалом.
и теория: алгоритмы, структуры данных, шаблоны проектирования.
Действительно, в React (да и в любом инструменте в принципе) проще разобраться, когда ты понимаешь, что происходит.
✔️ 3. React JS
Ну, конечно, нельзя стать React-разработчиком, не изучив React JS.
✔️ 4. Инструменты сборки
React - современный инструмент, который использует под капотом много технологий, поэтому необходимо особым образом организовывать свои проекты, чтобы они работали в реальных условиях, например, в браузере. Для этого нужно знать, что такое менеджеры пакетов (npm, yarn, ...) и сборщики (webpack, parcel, rollup, gulp...).
✔️ 5. Стилизация
React поддерживает множество подходов к стилизации компонентов (это мы уже проходили https://yangx.top/react_junior/142), и нужно иметь о них представление. Но автор статьи советует начать с Bootstrap.
✔️ 6. Управление состоянием
Состояние - важная концепция в React, поэтому его изучаем отдельно (да, мы так и делаем). В списке технологий: контекст, redux с кучей доп. пакетов), mobx, ...
✔️ 7. Проверка типов
Нужна, чтобы избежать многочисленных ошибок. Речь, прежде всего, о TypeScript.
✔️ 8. Обработка форм
Грамотная работа с формами - очень важная часть разработки, к счастью, у нас есть множество инструментов для этого (redux form, formik, formsy, final form).
✔️ 9. Маршрутизация
Необходима для создания API. Обеспечивается React Router https://yangx.top/react_junior/230.
✔️ 10. Клиенты API
Клиентские приложения чаще всего не изолированы от внешнего мира и работают в связке с сервером, поэтому нам нужны инструменты для обеспечения этой связки (от fetch до graphql).
✔️ 11. Вспомогательные библиотеки
Инструменты, которые берут на себя отдельные задачи и облегчают жизнь разработчика. В списке: Lodash, Moment, Classnames, ...
✔️ 12. Тестирование
Все знают, что тестирование очень важно. И у нас тут огромное количество инструментов для разных видов тестирования.
✔️ 13. Интернационализация
Очень комплексная задача, для решения которой тоже есть готовые инструменты (react intl, react i18next)
✔️ 14. SSR
Первым в списке идет Next.js, и автор считает, что этого достаточно (по крайней мере, для начала)
✔️ 15. Генераторы статических сайтов
Тут только Gatsby.js
✔️ 16. Интеграция с бэкенд-фреймворками
Например, React on Rails для интеграции с Rails.
✔️ 17. Мобильная разработка
React может работать не только в вебе. Для мобильной разработки предлагается React Native.
✔️ 18. Разработка для Desktop
Для десктопной разработки тоже есть решения: Proton Native, Electron, React Native Windows.
✔️ 19. Виртуальная реальность
Тут React 360.
#ссылки #инструменты
👍1
Расширение функциональности
Итак, мы имеем примерное представление об устройстве и работе хранилища в Redux https://yangx.top/react_junior/268.
Если встроенной функциональности нам недостаточно, то ее можно расширить. Для этого существуют так называемые store enhancers (усилители, энхансеры, не знаю, как назвать).
Проект: https://codesandbox.io/s/react-redux-enhancers-react-junior-j20kqm?file=/src/App.js
Энхансер оборачивает функцию
Структура энхансера
Энхансер - это декоратор. Он оборачивает функцию
То же самое можно сделать с методами
Использование энхансеров
Чтобы применить энхансер, его нужно передать в метод
Если энхансеров несколько, то их нужно объединить в один с помощью функции
#управлениесостоянием #redux #началоработы #примерыкода
Итак, мы имеем примерное представление об устройстве и работе хранилища в Redux https://yangx.top/react_junior/268.
Если встроенной функциональности нам недостаточно, то ее можно расширить. Для этого существуют так называемые store enhancers (усилители, энхансеры, не знаю, как назвать).
Проект: https://codesandbox.io/s/react-redux-enhancers-react-junior-j20kqm?file=/src/App.js
Энхансер оборачивает функцию
createStore
(как декоратор) и может изменить возвращаемый объект хранилища, например, создать собственные методы dispatch
, subscribe
или getState
.Структура энхансера
Энхансер - это декоратор. Он оборачивает функцию
createStore
, а значит должен вернуть функцию с такой же сигнатурой - замену оригинальной createStore
. В свою очередь эта функция должна вернуть объект хранилища со всеми необходимыми методами.
export const logDispatch = function(createStore) {
return function(rootReducer, preloadedState, enhancers) {
const store = createStore(rootReducer, preloadedState, enhancers)
function newDispatch(action) {
const result = store.dispatch(action)
console.log('Dispach:', { action, result })
return result
}
return { ...store, dispatch: newDispatch }
}
}
То же самое можно сделать с методами
subscribe
и getState
, но dispatch
, наверно, чаще изменяют таким способом.Использование энхансеров
Чтобы применить энхансер, его нужно передать в метод
createStore
третьим аргументом (после редьюсера и preloadedState`). Если `preloadedState
не указывается, то его можно опустить, тогда энхансер станет вторым аргументом.Если энхансеров несколько, то их нужно объединить в один с помощью функции
compose
.
import { compose, createStore } from "redux";
const composedEnhancer = compose(logDispatch, logGetState, logSubscribe);
const store = createStore(rootReducer, composedEnhancer);
#управлениесостоянием #redux #началоработы #примерыкода
Telegram
React Junior
Упрощенный код хранилища Redux
function createStore(reducer, preloadedState) {
let state = preloadedState
const listeners = []
function getState() {
return state
}
function subscribe(listener) {
listeners.push(listener)
return function…
function createStore(reducer, preloadedState) {
let state = preloadedState
const listeners = []
function getState() {
return state
}
function subscribe(listener) {
listeners.push(listener)
return function…
👍2👏1
Redux предоставляет нам один готовый энхансер -
Таким образом, мы можем логировать экшены, изменять их, а также - самое главное - выполнять различные асинхронные операции, связанные с полученным экшеном.
Структура миддлвара
У миддвара сложная структура - это целых три вложенных друг в друга функции. Две первые - обертки, которые выполняются только один раз при создании. Они нужны для передачи важных аргументов (методов хранилища и следующего миддлвара в цепочке), а третья - это непосредственно та функция, которая будет обрабатывать конкретный экшен, когда он будет вызван.
Использование миддлваров
Функция
При этом каждый миддлвар может прервать цепочку, если не вызовет метод
Функция
Для примера подключим просто несколько логгеров. При каждой отправке экшена они будут выводить в консоль сообщение.
https://codesandbox.io/s/react-redux-middleware-react-junior-obvtcs?file=/src/store/index.js
#управлениесостоянием #redux #началоработы #примерыкода #документация
applyMiddleware
. Он работает с методом dispatch
хранилища, то есть на участке между получением экшена и его реальной отправкой в редьюсер.Таким образом, мы можем логировать экшены, изменять их, а также - самое главное - выполнять различные асинхронные операции, связанные с полученным экшеном.
Структура миддлвара
У миддвара сложная структура - это целых три вложенных друг в друга функции. Две первые - обертки, которые выполняются только один раз при создании. Они нужны для передачи важных аргументов (методов хранилища и следующего миддлвара в цепочке), а третья - это непосредственно та функция, которая будет обрабатывать конкретный экшен, когда он будет вызван.
function exampleMiddleware(storeAPI) {
return function wrapDispatch(next) {
return function handleAction(action) {
return next(action)
}
}
}
Использование миддлваров
Функция
applyMiddleware
принимает неограниченное количество аргументов - миддлваров - функций для обработки экшена и выстраивает из них пайплайн. То есть экшен отправится сначала в первый миддлвар, потом во второй, и так далее по цепочке, пока не дойдет до самого метода store.dispatch
.При этом каждый миддлвар может прервать цепочку, если не вызовет метод
next
.Функция
applyMiddleware
- это обычный энхансер, значит, мы уже знаем, как ее подключить к хранилищу.Для примера подключим просто несколько логгеров. При каждой отправке экшена они будут выводить в консоль сообщение.
https://codesandbox.io/s/react-redux-middleware-react-junior-obvtcs?file=/src/store/index.js
#управлениесостоянием #redux #началоработы #примерыкода #документация
CodeSandbox
React + Redux. Middleware. React Junior - CodeSandbox
React + Redux. Middleware. React Junior by furrycat.web using nanoid, react, react-dom, react-redux, react-scripts, redux
👍2👏1
Зачем нужны миддлвары?
В миддлвары следует помещать весь код с сайд-эффектами, связанный с обработкой экшенов. Тот код, который нельзя поместить в редьюсер, и как-то не очень хочется помещать в компонент.
- логирование
- запросы к серверу и другой асинхронный API
- маршрутизацию приложения
- изменение экшенов
- задержка выполнения (или прекращение)
https://codesandbox.io/s/react-redux-async-actions-react-junior-t2npxd?file=/src/store/checking/index.js
Добавим в наше приложение проверку текста новой задачи перед ее добавлением в список. Представим, что у нас есть какой-то api (асинхронный), который умеет анализировать текст. Если задача полезная, будем выводить поощрительное сообщение, а если нет - то осуждающее (и не будем добавлять эту задачу в список).
Для этого:
- добавляем новый редьюсер (
- добавляем компонент
- создаем миддлвар
#управлениесостоянием #redux #началоработы #примерыкода #документация
В миддлвары следует помещать весь код с сайд-эффектами, связанный с обработкой экшенов. Тот код, который нельзя поместить в редьюсер, и как-то не очень хочется помещать в компонент.
- логирование
- запросы к серверу и другой асинхронный API
- маршрутизацию приложения
- изменение экшенов
- задержка выполнения (или прекращение)
https://codesandbox.io/s/react-redux-async-actions-react-junior-t2npxd?file=/src/store/checking/index.js
Добавим в наше приложение проверку текста новой задачи перед ее добавлением в список. Представим, что у нас есть какой-то api (асинхронный), который умеет анализировать текст. Если задача полезная, будем выводить поощрительное сообщение, а если нет - то осуждающее (и не будем добавлять эту задачу в список).
Для этого:
- добавляем новый редьюсер (
checkingReducer
) и набор экшенов (START_CHECKING
, FINISH_CHECKING
, SET_CHECKING_STATUS
;- добавляем компонент
CheckingStatus
, который отслеживает статус проверки и выводит сообщение;- создаем миддлвар
checkText
, который реагирует только на события добавления нового элемента в список. Он останавливает цепочку обработки экшена и отправляет запрос на проверку текста. Только после окончания проверки он запускает цепочку обработки дальше (если нет ошибки), и экшен отправляется в редьюсер.#управлениесостоянием #redux #началоработы #примерыкода #документация
CodeSandbox
React + Redux. Async actions. React Junior - CodeSandbox
React + Redux. Async actions. React Junior by furrycat.web using nanoid, react, react-dom, react-redux, react-scripts, redux
👍1
Экшены-функции
Еще один вариант - переместить код, связанный с экшеном в функцию-создатель экшена. Но тут есть проблема - у функций-создателей нет доступа к методу
Эту задачу тоже можно решить с помощью миддлваров. Нужно сделать так, чтобы вместо объекта экшена будет можно было отправлять функцию, а этой функции при отправке передать
https://codesandbox.io/s/react-redux-functional-actions-react-junior-zyleg0?file=/src/store/items/actions.js
#управлениесостоянием #redux #началоработы #примерыкода #документация
Еще один вариант - переместить код, связанный с экшеном в функцию-создатель экшена. Но тут есть проблема - у функций-создателей нет доступа к методу
store.dispatch
.Эту задачу тоже можно решить с помощью миддлваров. Нужно сделать так, чтобы вместо объекта экшена будет можно было отправлять функцию, а этой функции при отправке передать
dispatch
в качестве аргумента. Тогда она уже сама разберется, когда и как отправлять экшены.https://codesandbox.io/s/react-redux-functional-actions-react-junior-zyleg0?file=/src/store/items/actions.js
const handleFunction = function(storeAPI) {
return function(next) {
return function(action) {
if (typeof action === 'function') {
return action(storeAPI.dispatch, storeAPI.getState)
}
return next(action)
}
}
}
#управлениесостоянием #redux #началоработы #примерыкода #документация
CodeSandbox
React + Redux. Functional actions. React Junior - CodeSandbox
React + Redux. Functional actions. React Junior by furrycat.web using nanoid, react, react-dom, react-redux, react-scripts, redux
👍1
Thunk
И наконец, у Redux есть официальный миддлвар для обработки функциональных экшенов - пакет redux-thunk. Можно заменить нашу самописную
https://codesandbox.io/s/react-redux-thunk-react-junior-d71jls?file=/src/store/index.js
#управлениесостоянием #redux #началоработы #примерыкода #документация
И наконец, у Redux есть официальный миддлвар для обработки функциональных экшенов - пакет redux-thunk. Можно заменить нашу самописную
handleFunction
на него:https://codesandbox.io/s/react-redux-thunk-react-junior-d71jls?file=/src/store/index.js
#управлениесостоянием #redux #началоработы #примерыкода #документация
CodeSandbox
React + Redux. Thunk. React Junior - CodeSandbox
React + Redux. Thunk. React Junior by furrycat.web using nanoid, react, react-dom, react-redux, react-scripts, redux, redux-thunk
👍1
Redux: документация и туториалы
У Redux реально огромная и максимально подробная документация. Помимо прочего, там есть два официальных туториала:
* Redux Essentials - изучение сверху вниз, демонстрация лучших практик и распространенных кейсов.
* Redux Fundamentals - изучение снизу вверх, от основ, для лучшего понимания.
Мы, разумеется, начали снизу вверх, как я люблю)) Сначала основы, потом лучшие практики.
#redux #документация
У Redux реально огромная и максимально подробная документация. Помимо прочего, там есть два официальных туториала:
* Redux Essentials - изучение сверху вниз, демонстрация лучших практик и распространенных кейсов.
* Redux Fundamentals - изучение снизу вверх, от основ, для лучшего понимания.
Мы, разумеется, начали снизу вверх, как я люблю)) Сначала основы, потом лучшие практики.
#redux #документация
redux.js.org
Getting Started with Redux | Redux
Introduction > Getting Started: Resources to get started learning and using Redux
Поток данных в Redux
Визуализация однонаправленного потока данных: https://redux.js.org/assets/images/ReduxDataFlowDiagram-49fa8c3968371d9ef6f2a1486bd40a26.gif
- UI вызывает экшен
- он отправляется в редьюсер
- редьюсер изменяет состояние
- из-за этого изменяется UI
#redux #документация #управлениесостоянием
Визуализация однонаправленного потока данных: https://redux.js.org/assets/images/ReduxDataFlowDiagram-49fa8c3968371d9ef6f2a1486bd40a26.gif
- UI вызывает экшен
- он отправляется в редьюсер
- редьюсер изменяет состояние
- из-за этого изменяется UI
#redux #документация #управлениесостоянием
Основные концепции Redux
- Глобальное состояние является единственным источником правды для интерфейса, все данные находятся в одном месте. Так проще работать, и это проще отлаживать.
- Состояние доступно только для чтения. Любые изменения - только через экшены и редьюсер. Таким образом, интерфейс не сможет случайно переписать состояние.
- Иммутабельность состояния. Редьюсер не мутирует состояние, а создает его копию.
- Никакой асинхронной логики и сайд-эффектов в редьюсере. Это должна быть чистая функция, чтобы состояние всегда было предсказуемо.
#важно #управлениесостоянием #redux #документация
- Глобальное состояние является единственным источником правды для интерфейса, все данные находятся в одном месте. Так проще работать, и это проще отлаживать.
- Состояние доступно только для чтения. Любые изменения - только через экшены и редьюсер. Таким образом, интерфейс не сможет случайно переписать состояние.
- Иммутабельность состояния. Редьюсер не мутирует состояние, а создает его копию.
- Никакой асинхронной логики и сайд-эффектов в редьюсере. Это должна быть чистая функция, чтобы состояние всегда было предсказуемо.
#важно #управлениесостоянием #redux #документация
Использование useSelector
Важно: можно использовать хук
#управлениесостоянием #redux #началоработы #документация #важно
Важно: можно использовать хук
useSelector
несколько раз в одном компоненте, чтобы получать данные из хранилища отдельными маленькими порциями (особенно несвязанные данные). Документация называет это хорошей идеей.#управлениесостоянием #redux #началоработы #документация #важно
Асинхронный поток данных в Redux
Миддлвары позволяют добавлять в приложения асинхронную логику изменения состояния. Вот так это выглядит на схеме: https://redux.js.org/assets/images/ReduxAsyncDataFlowDiagram-d97ff38a0f4da0f327163170ccc13e80.gif
Обычный поток данных здесь: https://yangx.top/react_junior/277
#управлениесостоянием #redux #документация
Миддлвары позволяют добавлять в приложения асинхронную логику изменения состояния. Вот так это выглядит на схеме: https://redux.js.org/assets/images/ReduxAsyncDataFlowDiagram-d97ff38a0f4da0f327163170ccc13e80.gif
Обычный поток данных здесь: https://yangx.top/react_junior/277
#управлениесостоянием #redux #документация
Глобальное и локальное состояние
Должно ли все состояние приложения быть глобальным и содержаться в хранилище? Конечно, нет.
В глобальное состояние нужно выносить только минимально необходимый набор данных. Если вы не уверены, являются ли те или иные данные глобальными, документация Redux дает ряд подсказок:
- Знают ли другие части приложения об этих данных?
- Нужно ли вам на основе этих данных создавать какие-то другие производные данные (например, отфильтрованный список)?
- Используются ли эти данные в нескольких компонентах?
- Есть ли потребность в том, чтобы иметь возможность восстановить состояние этих данных для заданного момента времени (например, история действий пользователя)?
- Хотите ли вы кешировать эти данные (например, чтобы избежать нескольких запросов к серверу)?
- Хотите ли вы сохранить консистентность (согласованность) этих данных во время hot reloading (внутреннее состояние компонентов при этом может быть сброшено)?
Если на какие-то вопросы из списка вы ответили да, вероятно, вы имеете дело с глобальным состоянием.
#управлениесостоянием #redux #началоработы #документация
Должно ли все состояние приложения быть глобальным и содержаться в хранилище? Конечно, нет.
В глобальное состояние нужно выносить только минимально необходимый набор данных. Если вы не уверены, являются ли те или иные данные глобальными, документация Redux дает ряд подсказок:
- Знают ли другие части приложения об этих данных?
- Нужно ли вам на основе этих данных создавать какие-то другие производные данные (например, отфильтрованный список)?
- Используются ли эти данные в нескольких компонентах?
- Есть ли потребность в том, чтобы иметь возможность восстановить состояние этих данных для заданного момента времени (например, история действий пользователя)?
- Хотите ли вы кешировать эти данные (например, чтобы избежать нескольких запросов к серверу)?
- Хотите ли вы сохранить консистентность (согласованность) этих данных во время hot reloading (внутреннее состояние компонентов при этом может быть сброшено)?
Если на какие-то вопросы из списка вы ответили да, вероятно, вы имеете дело с глобальным состоянием.
#управлениесостоянием #redux #началоработы #документация
Почему редьюсер называется редьюсером
В JavaScript есть метод
Этот метод принимает в качестве аргумента функцию-коллбэк, которую вызывает для каждого значения в исходном массиве. Этот коллбэк получает два параметра:
-
-
Точно так же работает и редьюсер в Redux.
При первом вызове (для первого элемента массива),
При этом редьюсер не имеет никакого внутреннего состояния, он принимает два параметра и только на их основе вычисляет новое значение.
Если мы создадим массив экшенов и вызовем для него метод
#управлениесостоянием #redux #документация
В JavaScript есть метод
Array.reduce()
, который дает возможность превратить входной массив в одно единственное значение согласно какой-то логике - буквально уменьшить (reduce) массив до значения.Этот метод принимает в качестве аргумента функцию-коллбэк, которую вызывает для каждого значения в исходном массиве. Этот коллбэк получает два параметра:
-
previousResult
- предыдущее значение, которое было возвращено предыдущим вызовом коллбэка. По факту это накопленное на данный момент значение.-
currentItem
- текущий элемент массива, для которого вызывается коллбэк.Точно так же работает и редьюсер в Redux.
При первом вызове (для первого элемента массива),
previousResult
еще не существует, поэтому мы используем какое-то начальное значение.При этом редьюсер не имеет никакого внутреннего состояния, он принимает два параметра и только на их основе вычисляет новое значение.
Если мы создадим массив экшенов и вызовем для него метод
reduce
, то получим точно такой же результат, как если бы передавали все экшены по порядку в редьюсер вручную.
const actions = [
{ type: 'counter/incremented' },
{ type: 'counter/incremented' },
{ type: 'counter/incremented' }
]
const initialState = { value: 0 }
const finalResult = actions.reduce(counterReducer, initialState)
// {value: 3}
#управлениесостоянием #redux #документация
Redux DevTools
Redux DevTools - это расширение для браузера (доступно в Chrome и Firefox ). Оно дает возможность просматривать все изменения хранилища.
Чтобы расширение работало, нужно произвести некоторые настройки приложения - подключить специальный энхансер (расширитель функциональности хранилища).
Подключаем пакет
- Установите расширение
- Откройте панель разработчика - вкладка Redux
- Кликайте на кнопки
#управлениесостоянием #redux #инструменты
Redux DevTools - это расширение для браузера (доступно в Chrome и Firefox ). Оно дает возможность просматривать все изменения хранилища.
Чтобы расширение работало, нужно произвести некоторые настройки приложения - подключить специальный энхансер (расширитель функциональности хранилища).
Подключаем пакет
redux-devtools-extension
и импортируем из него функцию composeWithDevTools
. Это аналог функции compose
, но тут автоматически еще добавляется интеграция с браузерным расширением. import { composeWithDevTools } from "redux-devtools-extension";Посмотреть расширение в действии можно здесь: https://furrycat.ru/redux-test/
const store = createStore(rootReducer, composeWithDevTools());
- Установите расширение
- Откройте панель разработчика - вкладка Redux
- Кликайте на кнопки
#управлениесостоянием #redux #инструменты
Проблемы селекторов
Селекторы - удобные штуки, которые инкапсулируют в себе все общение с хранилищем, однако, у них есть ряд недостатков.
‼️ Проблема #1. Вызов на каждый чих
Селектор вызывается при каждом изменении хранилища, даже если изменилось что-то, что не имеет никакого отношения к этому селектору.
Если в селекторе происходят тяжелые вычисления, они будут выполнены в любом случае, даже если результат не изменится и ререндер не потребуется.
https://codesandbox.io/s/selectors-problems-1-react-junior-5f3kf7?file=/src/store.js
В хранилище есть два поля:
При изменении счетчика (события
‼️ Проблема #2. Преобразование ссылочных типов данных
Если у нас есть, например, массив каких-то значений (например, пользователей), а мы в селекторе хотим получить только идентификаторы этих пользователей, то мы используем метод массива
https://codesandbox.io/s/selectors-problems-2-react-junior-8mzn1u?file=/src/store.js
То есть тут все еще хуже, селектор не только вызывается постоянно, но и возвращает каждый раз новый результат, вызывая ререндер компонента без необходимости.
✅ Как решить эти проблемы - в следующем посте.
#управлениесостоянием #redux #оптимизация #важно
Селекторы - удобные штуки, которые инкапсулируют в себе все общение с хранилищем, однако, у них есть ряд недостатков.
‼️ Проблема #1. Вызов на каждый чих
Селектор вызывается при каждом изменении хранилища, даже если изменилось что-то, что не имеет никакого отношения к этому селектору.
Если в селекторе происходят тяжелые вычисления, они будут выполнены в любом случае, даже если результат не изменится и ререндер не потребуется.
https://codesandbox.io/s/selectors-problems-1-react-junior-5f3kf7?file=/src/store.js
В хранилище есть два поля:
items
и counter
. Они никак не связаны друг с другом. Есть также два селектора getItems
и getCounter
.При изменении счетчика (события
INCREMENT
, DECREMENT
) поле items
никак не меняется, даже ссылка на него остается прежней. Однако селектор getItems
все равно запускается. Он выполняется (возможно с какими-то сложными вычислениями), но возвращает то же самое значение, поэтому ререндера компонента List
не происходит.‼️ Проблема #2. Преобразование ссылочных типов данных
Если у нас есть, например, массив каких-то значений (например, пользователей), а мы в селекторе хотим получить только идентификаторы этих пользователей, то мы используем метод массива
.map()
. При этом каждый раз создается новый массив, даже если состоит он из тех же самых идентификаторов.https://codesandbox.io/s/selectors-problems-2-react-junior-8mzn1u?file=/src/store.js
То есть тут все еще хуже, селектор не только вызывается постоянно, но и возвращает каждый раз новый результат, вызывая ререндер компонента без необходимости.
✅ Как решить эти проблемы - в следующем посте.
#управлениесостоянием #redux #оптимизация #важно
CodeSandbox
Selectors problems 1. React Junior - CodeSandbox
Selectors problems 1. React Junior by furrycat.web using react, react-dom, react-redux, react-scripts, redux
👍2
Reselect - оптимизированные селекторы
В прошлом посте отметили две проблемы селекторов в Redux (возможно, есть еще). Теперь поговорим о решении.
Документация Redux рекомендует использовать библиотеку reselect для создания оптимизированных селекторов.
Идея заключается в том, чтобы отделить простое получение данных из хранилища и их преобразование в селекторе. До этого мы получали данные (
reselect предоставляет функцию
❔Как это работает
При изменении хранилища выполняются все "входные" селекторы. При этом результаты их работы кэшируются, поэтому можно сравнить новый результат с предыдущим. Если хотя бы один "входной" селектор вернет изменившийся результат, то будет вызван последний, "выходной" селектор, который пересчитает все, что нужно и при необходимости вызовет ререндер компонента.
✅ Решение проблемы #1 (тяжелые вычисления)
https://codesandbox.io/s/selectors-problems-1-reselect-react-junior-0lttp3
В качестве "входного" селектора используем функцию
"Выходной" селектор с тяжелым вычислением будет вызван и выполнен только если изменится результат работы "входного" селектора.
То есть мы разделяем две задачи: проверку изменений хранилища и собственно отбор нужных данных в селекторе.
✅ Решение проблемы #2 (маппинг массива)
https://codesandbox.io/s/selectors-problems-2-reselect-react-junior-33czrp?file=/src/components/List.js
Тут решение такое же, как и в прошлом примере. Результат преобразования зависит только от исходного значения. Поэтому мы выносим в отдельный "входной" селектор проверку
#управлениесостоянием #redux #оптимизация #важно
В прошлом посте отметили две проблемы селекторов в Redux (возможно, есть еще). Теперь поговорим о решении.
Документация Redux рекомендует использовать библиотеку reselect для создания оптимизированных селекторов.
Идея заключается в том, чтобы отделить простое получение данных из хранилища и их преобразование в селекторе. До этого мы получали данные (
store.items
) и что-то с ними делали (тяжелые вычисления или маппинг) в одной-единственной функции-селекторе, теперь же нужно разделить этот процесс на несколько функций - отдельно получить, отдельно посчитать.reselect предоставляет функцию
createSelector
, которая может принимать сколько угодно параметров-функций. При этом обработка данных происходит в последнем параметре, он называется "выходной" селектор. Все, что перед ним, - это "входные" селекторы, которые занимаются только получением данных из хранилища. ❔Как это работает
При изменении хранилища выполняются все "входные" селекторы. При этом результаты их работы кэшируются, поэтому можно сравнить новый результат с предыдущим. Если хотя бы один "входной" селектор вернет изменившийся результат, то будет вызван последний, "выходной" селектор, который пересчитает все, что нужно и при необходимости вызовет ререндер компонента.
✅ Решение проблемы #1 (тяжелые вычисления)
https://codesandbox.io/s/selectors-problems-1-reselect-react-junior-0lttp3
В качестве "входного" селектора используем функцию
getItemsList
, которая отслеживает только изменение store.items
. "Выходной" селектор с тяжелым вычислением будет вызван и выполнен только если изменится результат работы "входного" селектора.
То есть мы разделяем две задачи: проверку изменений хранилища и собственно отбор нужных данных в селекторе.
✅ Решение проблемы #2 (маппинг массива)
https://codesandbox.io/s/selectors-problems-2-reselect-react-junior-33czrp?file=/src/components/List.js
Тут решение такое же, как и в прошлом примере. Результат преобразования зависит только от исходного значения. Поэтому мы выносим в отдельный "входной" селектор проверку
store.items
. Если этот массив не меняется, то и селектор не будет вызван.#управлениесостоянием #redux #оптимизация #важно
Telegram
React Junior
Проблемы селекторов
Селекторы - удобные штуки, которые инкапсулируют в себе все общение с хранилищем, однако, у них есть ряд недостатков.
‼️ Проблема #1. Вызов на каждый чих
Селектор вызывается при каждом изменении хранилища, даже если изменилось что-то…
Селекторы - удобные штуки, которые инкапсулируют в себе все общение с хранилищем, однако, у них есть ряд недостатков.
‼️ Проблема #1. Вызов на каждый чих
Селектор вызывается при каждом изменении хранилища, даже если изменилось что-то…
IT-KAMASUTRA о Reselect
У меня была какая-то необъяснимая сложность в понимании reselect, возможно, документация не очень правильно о нем говорит, ну либо причина гораздо более простая 🤓.
В общем, мне немного помогли разобраться три видео из курса по React с канала IT-KAMASUTRA.
81 - React JS - селекторы (reselect part 1)
82 - React JS - mapStateToProps (reselect часть 2)
83 - React JS - подключаем reselect (reselect часть 3)
Есть одна сложность - в курсе речь идет о старой версии redux, в которой не было хуков
#ссылки #redux #управлениесостоянием
У меня была какая-то необъяснимая сложность в понимании reselect, возможно, документация не очень правильно о нем говорит, ну либо причина гораздо более простая 🤓.
В общем, мне немного помогли разобраться три видео из курса по React с канала IT-KAMASUTRA.
81 - React JS - селекторы (reselect part 1)
82 - React JS - mapStateToProps (reselect часть 2)
83 - React JS - подключаем reselect (reselect часть 3)
Есть одна сложность - в курсе речь идет о старой версии redux, в которой не было хуков
useDispatch
и useSelect
. Там все было посложнее, использовался компонент высшего порядка (connect
), а глобальное состояние преобразовывалось в пропсы с помощью функций mapStateToProps
и mapDispatchToProps
. Это может вызвать трудности.#ссылки #redux #управлениесостоянием
YouTube
81 - React JS - селекторы (reselect part 1)
https://it-incubator.eu/education - человекоориентированное, честное и профессиональное обучение front-end и back-end разработке гарантированно до трудоустройства за фиксированную стоимость.
Поддержать меня можно на patreon https://www.patreon.com/itkamasutra…
Поддержать меня можно на patreon https://www.patreon.com/itkamasutra…
Reselect
Библиотека для создания мемоизированных селекторов от создателей redux: https://github.com/reduxjs/reselect
Позволяет вычислять "производное" состояние (в хранилище остаются только минимально необходимые данные, все остальное вычисляется).
Селекторы пересчитываются, только если изменяются их зависимости.
Кроме того, созданные селекторы можно использовать как "входные" для других селекторов.
createSelector (еще раз для полного осознания)
Для создания селектора используется функция
При вызове такого селектора под капотом сначала вызываются все входные селекторы (с полученными аргументами). Если они возвращают новое значение (отличное от того, которое было при предыдущем вызове), то вызывается выходной селектор. При этом аргументами для выходного селектора являются результаты работы входных селекторов. Если же все входные селекторы возвращают тот же результат, что и раньше, то выходной селектор не запускается, вместо этого просто возвращается значение, закешированное с прошлого раза.
Для сравнения результатов используется алгоритм строгого сравнения (
Размер кэша
По умолчанию размер кэша у такого селектора равен 1. Это значит, что хранится только одно предыдущее значение для каждого селектора.
Подробнее - в документации. Там есть утилитарные функции для мемоизации и ряд опций для настройки, а также FAQ с распространенными проблемами.
#redux #управлениесостоянием
Библиотека для создания мемоизированных селекторов от создателей redux: https://github.com/reduxjs/reselect
Позволяет вычислять "производное" состояние (в хранилище остаются только минимально необходимые данные, все остальное вычисляется).
Селекторы пересчитываются, только если изменяются их зависимости.
Кроме того, созданные селекторы можно использовать как "входные" для других селекторов.
createSelector (еще раз для полного осознания)
Для создания селектора используется функция
createSelector
. Она принимает один или несколько "входных" селекторов (в виде массива или просто отдельными аргументами) и один "выходной". Еще может принимать объект с настройками.При вызове такого селектора под капотом сначала вызываются все входные селекторы (с полученными аргументами). Если они возвращают новое значение (отличное от того, которое было при предыдущем вызове), то вызывается выходной селектор. При этом аргументами для выходного селектора являются результаты работы входных селекторов. Если же все входные селекторы возвращают тот же результат, что и раньше, то выходной селектор не запускается, вместо этого просто возвращается значение, закешированное с прошлого раза.
Для сравнения результатов используется алгоритм строгого сравнения (
===
, сравнение по ссылке). Размер кэша
По умолчанию размер кэша у такого селектора равен 1. Это значит, что хранится только одно предыдущее значение для каждого селектора.
Подробнее - в документации. Там есть утилитарные функции для мемоизации и ряд опций для настройки, а также FAQ с распространенными проблемами.
#redux #управлениесостоянием
👏1
Валидация форм в React-приложениях с помощью хука useForm
Статья (англ.): https://blog.openreplay.com/react-form-validation-with-the-useform-hook
Валидация форм в вебе - очень важная задача, которая так до сих пор и не стандартизирована полноценно. Существуют десятки разных решений, и в статье разбирается одно из них - библиотека React Hook Form https://react-hook-form.com/get-started.
Эта библиотека небольшая, производительная и довольно популярная, как понятно из названия она использует хуки, которые де-факто являются сейчас стандартом в React разработке.
Предлагаемый библиотекой api интуитивно понятный, хоть и немного громоздкий (впрочем, где вы видели негромоздкую валидацию, да?)
https://codesandbox.io/s/react-hook-form-react-junior-qyv1if?file=/src/App.js
Все базовые потребности есть: установка правил валидации, вывод ошибок, отслеживание изменений, отслеживание фокуса и т.д.
Использование
Хук
*
* в
*
Регистрация поля
Функция
Кроме того, можно установить собственную функцию для валидации.
formState
Содержит флаги
#ссылки #валидацияформ
Статья (англ.): https://blog.openreplay.com/react-form-validation-with-the-useform-hook
Валидация форм в вебе - очень важная задача, которая так до сих пор и не стандартизирована полноценно. Существуют десятки разных решений, и в статье разбирается одно из них - библиотека React Hook Form https://react-hook-form.com/get-started.
Эта библиотека небольшая, производительная и довольно популярная, как понятно из названия она использует хуки, которые де-факто являются сейчас стандартом в React разработке.
Предлагаемый библиотекой api интуитивно понятный, хоть и немного громоздкий (впрочем, где вы видели негромоздкую валидацию, да?)
https://codesandbox.io/s/react-hook-form-react-junior-qyv1if?file=/src/App.js
Все базовые потребности есть: установка правил валидации, вывод ошибок, отслеживание изменений, отслеживание фокуса и т.д.
Использование
Хук
useForm
может принимать базовые настройки валидации (можно ничего не передавать и использовать дефолтные) и возвращает несколько методов (`register`, handleSubmit`), а также объект `formState
. По названиям очевидно, для чего они предназначены:*
register
- регистрирует каждое валидируемое поле с конкретными настройками валидации.* в
handleSubmit
нужно передать функцию, которая будет вызвана при удачной отправке формы. Обычно такие методы вызываются на событие form.onsubmit
.*
formState
содержит актуальную информацию, включая ошибки валидации.Регистрация поля
Функция
register
принимает имя поля и объект с настройками валидации и возвращает набор атрибутов для контрола (для отслеживания фокуса и изменений значения). Есть ряд базовых опций, таких как required
, minLength
, maxLength
, pattern
. Для каждой настройки можно просто ставить true
или конкретное значение (например, минимальная длина или паттерн), а можно передать объект с полями value
и message
. Кроме того, можно установить собственную функцию для валидации.
formState
Содержит флаги
isSubmitted
, isValid
, объект с ошибками errors
и др.#ссылки #валидацияформ
Openreplay
React Form Validation with the useForm Hook
Learn how to add validation on your React forms using this detailed tutorial
👍1👏1