Forwarded from Cat in Web
Шахматы на React и TypeScript С НУЛЯ. Практикуем ООП
Видео (рус.): https://www.youtube.com/watch?v=mUvYGUYMvKo
Часовое (1 час 12 минут) руководство по созданию шахмат на React. Все последовательно и очень понятно, даже если вы (как я) не особенно близко знакомы с TypeScript. Если не планируете повторять, можно смотреть на скорости 1.5.
Логика игры максимально отделена от представления, поэтому вместо React ее можно реализовать на чем угодно.
Модели
👉 Класс
👉 Класс
👉 Класс
Все эти классы связаны: доска может обращаться к своим клеткам, клетки имеют ссылку на доску и на фигуры, которые на них стоят, а фигуры могут ссылаться на свою клетку. В целом это не очень хорошая практика, так как образуются кольцевые зависимости, но она позволяет наладить довольно удобное взаимодействие.
В видео полностью реализована логика перемещения фигур, переход хода и даже таймер игры. Но есть так же несколько задач для "домашней работы".
Мое повторение за автором: https://codesandbox.io/s/checkmate-react-ts-o8ob16?file=/src/models/Player.ts
#react #video #typescript
Видео (рус.): https://www.youtube.com/watch?v=mUvYGUYMvKo
Часовое (1 час 12 минут) руководство по созданию шахмат на React. Все последовательно и очень понятно, даже если вы (как я) не особенно близко знакомы с TypeScript. Если не планируете повторять, можно смотреть на скорости 1.5.
Логика игры максимально отделена от представления, поэтому вместо React ее можно реализовать на чем угодно.
Модели
👉 Класс
Board
(игровая доска) создает игровое поле и расставляет фигуры.👉 Класс
Cell
(клетка доски) имеет цвет, координаты и знает, какая фигура на ней находится👉 Класс
Figure
(фигура) и 6 дочерних классов для отдельных фигур хранят логику передвижения фигур по доске.Все эти классы связаны: доска может обращаться к своим клеткам, клетки имеют ссылку на доску и на фигуры, которые на них стоят, а фигуры могут ссылаться на свою клетку. В целом это не очень хорошая практика, так как образуются кольцевые зависимости, но она позволяет наладить довольно удобное взаимодействие.
В видео полностью реализована логика перемещения фигур, переход хода и даже таймер игры. Но есть так же несколько задач для "домашней работы".
Мое повторение за автором: https://codesandbox.io/s/checkmate-react-ts-o8ob16?file=/src/models/Player.ts
#react #video #typescript
YouTube
Шахматы на React и TypeScript С НУЛЯ. Практикуем ООП
В этом ролике мы разработаем свои шахматы на React и typescript. Попрактикуем ООП. Шахматы на Javascript.
Мой курс "Продвинутый Frontend. В production на React" - https://ulbitv.ru/frontend
Initial шаблон для проекта с фигурками и финальный исходный код…
Мой курс "Продвинутый Frontend. В production на React" - https://ulbitv.ru/frontend
Initial шаблон для проекта с фигурками и финальный исходный код…
👍1
7 расширений VS Code, которые стоит знать разработчику React
Статья: https://nuancesprog.ru/p/15719/
1. React Style Helper
Упрощает написание стилей в JSX, поддерживает препроцессоры, есть автодополнение и go-to-definition.
2. VS Code React Refactor
Полезное приложение для рефакторинга, например, может извлекать фрагмент в JSX в отдельный компонент.
3. React PropTypes Intellisense
Находит PropTypes компонента и предлагает их для автодополнения.
4. ES7+ React/Redux/React-Native snippets
Полезные сниппеты.
5. Git Lens
Множество удобных функций для работы с историей изменений. Полезно любому разработчику.
6. Color Highlight
Находит hex-коды цветов и подсвечивает их нужным цветом.
7. React Documentation
Отображает подсказки из встроенной документации для методов и свойств.
#инструменты #ссылки
Статья: https://nuancesprog.ru/p/15719/
1. React Style Helper
Упрощает написание стилей в JSX, поддерживает препроцессоры, есть автодополнение и go-to-definition.
2. VS Code React Refactor
Полезное приложение для рефакторинга, например, может извлекать фрагмент в JSX в отдельный компонент.
3. React PropTypes Intellisense
Находит PropTypes компонента и предлагает их для автодополнения.
4. ES7+ React/Redux/React-Native snippets
Полезные сниппеты.
5. Git Lens
Множество удобных функций для работы с историей изменений. Полезно любому разработчику.
6. Color Highlight
Находит hex-коды цветов и подсвечивает их нужным цветом.
7. React Documentation
Отображает подсказки из встроенной документации для методов и свойств.
#инструменты #ссылки
NOP::Nuances of programming
7 расширений VS Code, которые стоит знать разработчику React
Работаете с React? Используйте эти 7 расширений, чтобы повысить свою продуктивность.
👍5
Forwarded from Cat in Web
Событийный цикл: микрозадачи и макрозадачи
Оригинал из learn.javascript: https://learn.javascript.ru/event-loop
Прекрасная статья из прекрасного учебника про основную концепцию JavaScript: цикл событий.
Цикл событий состоит из итераций, потому он и цикл. Каждая итерация начинается с выполнения "макротаска". Например, написанный вами синхронный код - это макротаск, и цикл событий начинается с его выполнения.
Когда макротаск выполнен, проверяется очередь микротасков. Это в основном промисы, а точнее блоки
Итак, сначала выполняется ваш синхронный код, а затем все готовые промисы. Причем, все сразу, так что у них получается один контекст выполнения.
И только после опустошения очереди микротасков происходит рендеринг - обновление страницы. Если ваш синхронный код что-то поменял на странице, появится это изменение только сейчас, после того, как обработаны все готовые промисы.
После этого начинается следующая итерация цикла событий. Для нее берется новый макротаск. Но откуда он берется, если весь код уже выполнен? Это различные асинхронные действия (кроме промисов). Это может быть выполнившийся setTimeout, пришедший ответ сервера или пользовательское событие, например, клик. При этом макротаск берется самый старый, который ждет дольше всех.
После того как он выполнится, снова запускаются все микротаски, которые готовы к этому моменту. И лишь после этого выполняется рендеринг - внесение изменений на страницу.
Итак, одна итерация цикла событий:
- один макротаск (самый старый из очереди) - синхронный код, setTimeout, ответы API, пользовательские события
- все готовые микротаски (обработчики промисов)
- рендеринг
После статьи есть задачки на понимание последовательности выполнения операций - несложные и полезные.
#javascript #eventloop #основныеконцепции
Оригинал из learn.javascript: https://learn.javascript.ru/event-loop
Прекрасная статья из прекрасного учебника про основную концепцию JavaScript: цикл событий.
Цикл событий состоит из итераций, потому он и цикл. Каждая итерация начинается с выполнения "макротаска". Например, написанный вами синхронный код - это макротаск, и цикл событий начинается с его выполнения.
Когда макротаск выполнен, проверяется очередь микротасков. Это в основном промисы, а точнее блоки
.then
, .catch
, .finally
, которые готовы выполниться. Тело промиса выполняется синхронно, то есть входит в макротаск.Итак, сначала выполняется ваш синхронный код, а затем все готовые промисы. Причем, все сразу, так что у них получается один контекст выполнения.
И только после опустошения очереди микротасков происходит рендеринг - обновление страницы. Если ваш синхронный код что-то поменял на странице, появится это изменение только сейчас, после того, как обработаны все готовые промисы.
После этого начинается следующая итерация цикла событий. Для нее берется новый макротаск. Но откуда он берется, если весь код уже выполнен? Это различные асинхронные действия (кроме промисов). Это может быть выполнившийся setTimeout, пришедший ответ сервера или пользовательское событие, например, клик. При этом макротаск берется самый старый, который ждет дольше всех.
После того как он выполнится, снова запускаются все микротаски, которые готовы к этому моменту. И лишь после этого выполняется рендеринг - внесение изменений на страницу.
Итак, одна итерация цикла событий:
- один макротаск (самый старый из очереди) - синхронный код, setTimeout, ответы API, пользовательские события
- все готовые микротаски (обработчики промисов)
- рендеринг
После статьи есть задачки на понимание последовательности выполнения операций - несложные и полезные.
#javascript #eventloop #основныеконцепции
learn.javascript.ru
Событийный цикл: микрозадачи и макрозадачи
👍4
Вещи, которые полезно знать о React.js
Статья (рус.): https://habr.com/ru/post/679452/
Несколько не самых передовых концепций React, о которых можно забыть, если регулярно не использовать.
1. Функция сброса в useEffect срабатывает при каждом перерендеринге компонента, а не только при размонтировании. Она объединяет в себе функциональность методов componentDidUpdate и componentWillUnmount.
2. Весь код внутри функционального компонента вызывается при каждом перерендере. Чтобы этого не происходило, нужно использовать хуки useEffect (для сайд-эффектов) и useMemo (для сложных вычислений) с указанием зависимостей.
3. Не следует помещать вызов функции в хук useState, так как этот вызов будет происходить при каждом перерендере. Если необходимо произвести вычисление для установки начального состояния, передайте в useState саму функцию. Она вызовется один раз.
4. Метод для изменения состояния, полученный из useState, может принимать функцию. Ее следует использовать, если новое состояние зависит от предыдущего.
5. Кроме useEffect есть еще useLayoutEffect, который отрабатывает синхронно и позволяет избежать мигания при манипуляциях с DOM.
#ссылки #оптимизация #хуки
Статья (рус.): https://habr.com/ru/post/679452/
Несколько не самых передовых концепций React, о которых можно забыть, если регулярно не использовать.
1. Функция сброса в useEffect срабатывает при каждом перерендеринге компонента, а не только при размонтировании. Она объединяет в себе функциональность методов componentDidUpdate и componentWillUnmount.
2. Весь код внутри функционального компонента вызывается при каждом перерендере. Чтобы этого не происходило, нужно использовать хуки useEffect (для сайд-эффектов) и useMemo (для сложных вычислений) с указанием зависимостей.
3. Не следует помещать вызов функции в хук useState, так как этот вызов будет происходить при каждом перерендере. Если необходимо произвести вычисление для установки начального состояния, передайте в useState саму функцию. Она вызовется один раз.
4. Метод для изменения состояния, полученный из useState, может принимать функцию. Ее следует использовать, если новое состояние зависит от предыдущего.
5. Кроме useEffect есть еще useLayoutEffect, который отрабатывает синхронно и позволяет избежать мигания при манипуляциях с DOM.
#ссылки #оптимизация #хуки
Хабр
Вещи, которые полезно знать о React.js
Несколько слов о мотивации написать эту статью. Большинство вещей, о которых я тут хочу рассказать, вы можете узнать из документации React. Но проводя собеседования последние пару лет я понял, что...
👍6
Redux: динамическое добавление редьюсеров
Чтобы иметь возможность разделять код и подгружать что-то по мере необходимости (code splitting), нам нужна возможность динамически добавлять редьюсеры в хранилище. То есть при подгрузке нового функционала, нужно добавить новый редьюсер для работы с ним.
Основной принцип заключается с использовании метода хранилища
При добавлении нового редьюсера мы должны объединить его с уже добавленными с помощью
В документации описано два подхода реализации этого механизма:
- добавление хранилищу нового метода
- создание отдельного объекта - Менеджера Редьюсеров, который внутри себя реализует всю логику и отдает корневой редьюсер, который формируется динамически.
#документация #управлениесостоянием #redux #оптимизация
Чтобы иметь возможность разделять код и подгружать что-то по мере необходимости (code splitting), нам нужна возможность динамически добавлять редьюсеры в хранилище. То есть при подгрузке нового функционала, нужно добавить новый редьюсер для работы с ним.
Основной принцип заключается с использовании метода хранилища
store.replaceReducer
. Как следует из названия он заменяет старый корневой редьюсер на новый. При добавлении нового редьюсера мы должны объединить его с уже добавленными с помощью
combineReducers
, а затем заменить полученным результатом старый корневой редьюсер.В документации описано два подхода реализации этого механизма:
- добавление хранилищу нового метода
injectReducer
- создание отдельного объекта - Менеджера Редьюсеров, который внутри себя реализует всю логику и отдает корневой редьюсер, который формируется динамически.
#документация #управлениесостоянием #redux #оптимизация
redux.js.org
Code Splitting | Redux
In large web applications, it is often desirable to split up the app code into multiple JS bundles that can be loaded on-demand. This strategy, called 'code splitting', helps to increase performance of your application by reducing the size of the initial…
👍2🤩1
Совместное использование данных разными редьюсерами
Для удобства мы обычно разделяем состояние на отдельные поля и создаем свой редьюсер для каждого (слайсы). Функция
Но может потребоваться, чтобы редьюсер имел доступ к другой части состояния.
В документации есть отдельная глава с разбором этой ситуации: Beyond combineReducers
Тут есть несколько вариантов реализации:
- обработка экшенов переносится в корневой редьюсер, который вызывает слайс-редьюсеры со всеми необходимыми аргументами
- в объект экшена добавляется все необходимое состояние
- добавление еще одного редьюсера поверх
Главная идея тут в том, что
#управлениесостоянием #документация #redux
Для удобства мы обычно разделяем состояние на отдельные поля и создаем свой редьюсер для каждого (слайсы). Функция
combineReducers
объединяет их в один корневой редьюсер. При поступлении экшена каждый слайс-редьюсер работает со своей частью состояния.Но может потребоваться, чтобы редьюсер имел доступ к другой части состояния.
combineReducers
таких возможностей не предоставляет, потребуется написать свою логику.В документации есть отдельная глава с разбором этой ситуации: Beyond combineReducers
Тут есть несколько вариантов реализации:
- обработка экшенов переносится в корневой редьюсер, который вызывает слайс-редьюсеры со всеми необходимыми аргументами
- в объект экшена добавляется все необходимое состояние
- добавление еще одного редьюсера поверх
combineReducers
с обработкой отдельных случаевГлавная идея тут в том, что
combineReducers
это всего лишь простая функция, реализующая частый сценарий объединения слайс-редьюсеров. Мы не обязаны использовать ее, а если используем, то можем смело изменять при необходимости. Главное - понимать, что там под капотом.#управлениесостоянием #документация #redux
redux.js.org
Beyond combineReducers | Redux
Structuring Reducers > Beyond combineReducers: Examples of reducer logic for other use cases not handled by combineReducers
👍1
Переиспользование логики в редьюсерах
Статья из документации: Reusing Reducer Logic
Статья рассматривает случай, если у вас в состоянии есть три одинаковых счетчика с одинаковыми экшенами. Чтобы не дублировать логику для каждого счетчика, есть несколько способов:
- самый очевидный - использовать редьюсер высшего порядка, который принимает имя счетчика и возвращает функцию-редьюсер, настроенную должным образом (с проверкой имени или уникальными именами экшенов)
- собрать счетчики в коллекцию (массив или объект) и передавать в экшен имя или индекс нужного счетчика
Полезно посмотреть, чтобы расширить представление о том, что можно делать с редьюсерами.
#управлениесостоянием #документация #redux
Статья из документации: Reusing Reducer Logic
Статья рассматривает случай, если у вас в состоянии есть три одинаковых счетчика с одинаковыми экшенами. Чтобы не дублировать логику для каждого счетчика, есть несколько способов:
- самый очевидный - использовать редьюсер высшего порядка, который принимает имя счетчика и возвращает функцию-редьюсер, настроенную должным образом (с проверкой имени или уникальными именами экшенов)
- собрать счетчики в коллекцию (массив или объект) и передавать в экшен имя или индекс нужного счетчика
Полезно посмотреть, чтобы расширить представление о том, что можно делать с редьюсерами.
#управлениесостоянием #документация #redux
redux.js.org
Reusing Reducer Logic | Redux
Structuring Reducers > Reusing Reducer Logic: Patterns for creating reusable reducers
👍1
Иммутабельное обновление состояния: паттерны
Статья из документации (англ.): Immutable Update Patterns
В статье демонстрируются примеры и рассматриваются основные ошибки при обновлении состояния в редьюсерах.
Мы помним, что Redux полагается на то, что состояние не мутирует, а редьюсер возвращает новую ссылку, если состояние изменилось. Важно соблюдать это соглашение, иначе изменения не отобразятся в компонентах.
Речь идет о глубоком копировании объектов на всех уровнях (не только на первом). К счастью, у нас есть spread-оператор, который делает это удобнее.
В статье есть примеры вставки, удаления и обновления элемента массива.
Кроме того, перечислены некоторые утилитарные инструменты.
#управлениесостоянием #документация #redux
Статья из документации (англ.): Immutable Update Patterns
В статье демонстрируются примеры и рассматриваются основные ошибки при обновлении состояния в редьюсерах.
Мы помним, что Redux полагается на то, что состояние не мутирует, а редьюсер возвращает новую ссылку, если состояние изменилось. Важно соблюдать это соглашение, иначе изменения не отобразятся в компонентах.
Речь идет о глубоком копировании объектов на всех уровнях (не только на первом). К счастью, у нас есть spread-оператор, который делает это удобнее.
В статье есть примеры вставки, удаления и обновления элемента массива.
Кроме того, перечислены некоторые утилитарные инструменты.
#управлениесостоянием #документация #redux
redux.js.org
Immutable Update Patterns | Redux
Structuring Reducers > Immutable Update Patterns: How to correctly update state immutably, with examples of common mistakes
👍1
Повторение по селекторам
Статья в документации: https://redux.js.org/usage/deriving-data-selectors
Селекторы - это обычные функции, которые получают на вход состояние приложения (чаще полное состояние, а не отдельные части) и возвращают какие-то данные из него (возможно, обработанные). Например, селектор может возвращать полный список элементов TODO-листа, а может фильтровать его по статусу.
Зачем нужны селекторы
Использование селекторов позволяет сохранять состояние максимально чистым (все, что можно вычислить, вычисляется в селекторах), а также дает возможность переиспользовать логику выбора данных (один селектор можно использовать в нескольких местах). Это особенно удобно, если селектор достает данные из глубин состояния (третий-четвертый уровень вложенности).
В общем, в селекторах инкапсулируется логика получения данных из состояния. Они знают структуру состояния и как достать нужные данные. В идеале, это знание не должно выходить за пределы селекторов и редьюсера. Компоненты не должны заботиться об устройстве состояния, они хотят только получать нужные данные.
Организация селекторов
Документация рекомендует давать функция-селекторам осмысленные имена, начинающиеся с
Селекторы обычно располагаются в файлах слайсов, рядом с логикой редьюсера. Отдельные селекторы могут находиться и в компонентах (специфичные селекторы, которые не переиспользуются в других местах). Селекторы также могут находиться внутри thunks, так как там есть доступ к полному состоянию.
Селекторы применяются вместе с хуком
Проблемы
Внутри селекторов могут производиться достаточно сложные вычисления, поэтому следует минимизировать количество их запусков. Однако селекторы запускаются при каждом изменении состояния, причем все селекторы, даже те, которые не имеют отношения к изменившимся данным.
Хук
Чтобы избежать этого, нужна мемоизация селекторов. (Мемоизация не нужна, если селектор возвращает примитивное значение).
Мемоизация
Для мемоизации мы используем библиотеку Reselect (есть и альтернативы, которые указаны в статье). Она предоставляет функцию
#управлениесостоянием #документация #redux #оптимизация
Статья в документации: https://redux.js.org/usage/deriving-data-selectors
Селекторы - это обычные функции, которые получают на вход состояние приложения (чаще полное состояние, а не отдельные части) и возвращают какие-то данные из него (возможно, обработанные). Например, селектор может возвращать полный список элементов TODO-листа, а может фильтровать его по статусу.
Зачем нужны селекторы
Использование селекторов позволяет сохранять состояние максимально чистым (все, что можно вычислить, вычисляется в селекторах), а также дает возможность переиспользовать логику выбора данных (один селектор можно использовать в нескольких местах). Это особенно удобно, если селектор достает данные из глубин состояния (третий-четвертый уровень вложенности).
В общем, в селекторах инкапсулируется логика получения данных из состояния. Они знают структуру состояния и как достать нужные данные. В идеале, это знание не должно выходить за пределы селекторов и редьюсера. Компоненты не должны заботиться об устройстве состояния, они хотят только получать нужные данные.
Организация селекторов
Документация рекомендует давать функция-селекторам осмысленные имена, начинающиеся с
select
.Селекторы обычно располагаются в файлах слайсов, рядом с логикой редьюсера. Отдельные селекторы могут находиться и в компонентах (специфичные селекторы, которые не переиспользуются в других местах). Селекторы также могут находиться внутри thunks, так как там есть доступ к полному состоянию.
Селекторы применяются вместе с хуком
useSelector
.Проблемы
Внутри селекторов могут производиться достаточно сложные вычисления, поэтому следует минимизировать количество их запусков. Однако селекторы запускаются при каждом изменении состояния, причем все селекторы, даже те, которые не имеют отношения к изменившимся данным.
Хук
useSelector
сравнивает результат выполнения селектора с предыдущим (используя строгое равенство `===`). Если значения отличаются, выполняется перерендер. То есть селектор не должен возвращать новое значение, если ничего не изменилось. Но тут появляется проблема, например, с методами массивов (map, filter), которые всегда возвращают новый массив. Даже если список отфильтрованных элементов не изменился, хук увидит новый массив и посчитает, что нужен перерендер.Чтобы избежать этого, нужна мемоизация селекторов. (Мемоизация не нужна, если селектор возвращает примитивное значение).
Мемоизация
Для мемоизации мы используем библиотеку Reselect (есть и альтернативы, которые указаны в статье). Она предоставляет функцию
createSelector
, которая принимает любое количество входных селекторов (для проверки изменения различных частей состояния) и один выходной (собственно для выборки данных). Выходной селектор вызывается только в том случае, если входные селекторы возвращают изменившиеся результаты.#управлениесостоянием #документация #redux #оптимизация
redux.js.org
Deriving Data with Selectors | Redux
Usage > Redux Logic > Selectors: deriving data from the Redux state
👍3
Реализация функциональности Шаг назад
Статья в документации: https://redux.js.org/usage/implementing-undo-history
В статье описано, как реализовать в Redux-приложении функционал Шаг назад/вперед. В Redux это особенно просто, так как все состояние хранится в одном объекте и при каждом изменении оно представлено новым объектом - значит легко хранить последовательность состояний. К тому же вся логика управления состоянием находится в функции (редьюсере). Здесь можно использовать паттерн декоратор, чтобы добавить новый функционал, не ломая основной.
Глобально паттерн выглядит так:
Текущее состояние хранится в поле
В статье дана полная реализация алгоритма. Также можно воспользоваться готовой реализацией из пакета redux-undo.
#управлениесостоянием #redux #документация #паттерны
Статья в документации: https://redux.js.org/usage/implementing-undo-history
В статье описано, как реализовать в Redux-приложении функционал Шаг назад/вперед. В Redux это особенно просто, так как все состояние хранится в одном объекте и при каждом изменении оно представлено новым объектом - значит легко хранить последовательность состояний. К тому же вся логика управления состоянием находится в функции (редьюсере). Здесь можно использовать паттерн декоратор, чтобы добавить новый функционал, не ломая основной.
Глобально паттерн выглядит так:
{
past: [T, T],
present: T,
future: [T]
}
Текущее состояние хранится в поле
present
. При каждом изменении старое состояние добавляется в массив past
, а present
изменяется. Если потребуется сделать Шаг назад, мы просто возьмем последнее состояние из past
и установим его в present
. При этом текущее состояние нужно сохранить в future
, чтобы к нему можно было вернуться.В статье дана полная реализация алгоритма. Также можно воспользоваться готовой реализацией из пакета redux-undo.
#управлениесостоянием #redux #документация #паттерны
redux.js.org
Implementing Undo History | Redux
- Completion of the "Redux Fundamentals" tutorial
👍3
Я все время неправильно создавал формы в React
Статья (англ.): https://dev.to/kuvambhardwaj/i-was-creating-forms-the-wrong-way-all-along-in-reactjs-hl3
Автор делится своим подходом к созданию форм в React. Вместо многочисленных
Выглядит такой подход действительно намного изящнее, однако в то же время он лишен некоторых преимуществ. В частности тут мы имеем дело с неконтролируемыми полями ввода, а значит, не можем следить за их значениями.
Если вам все же нужны контролируемые поля внутри формы, автор предлагает смешивать подходы, что выглядит уже грязновато.
В любом случае статья полезна, так как напоминает, что внутри React не следует забывать о нативных возможностях языка и окружения.
#формы #ссылки #паттерны
Статья (англ.): https://dev.to/kuvambhardwaj/i-was-creating-forms-the-wrong-way-all-along-in-reactjs-hl3
Автор делится своим подходом к созданию форм в React. Вместо многочисленных
useState
и onChange
для каждого поля ввода он использует нативные возможности HTML: тег form
, атрибуты name
и структуру FormData
.Выглядит такой подход действительно намного изящнее, однако в то же время он лишен некоторых преимуществ. В частности тут мы имеем дело с неконтролируемыми полями ввода, а значит, не можем следить за их значениями.
Если вам все же нужны контролируемые поля внутри формы, автор предлагает смешивать подходы, что выглядит уже грязновато.
В любом случае статья полезна, так как напоминает, что внутри React не следует забывать о нативных возможностях языка и окружения.
#формы #ссылки #паттерны
DEV Community
I was creating Forms the wrong way all along in React.js 🤔
Introduction When I was creating a signup form, I found myself creating dozens of...
👍3
Управление состоянием в React: продолжение
В рамках темы управления состоянием мы разобрались со связкой
В документации Redux еще осталось несколько интересных разделов (Faq, Style Guide, Api Reference), но информация в них во многом повторяется, поэтому пока можно пойти дальше, а к ним вернуться на досуге.
Кроме того, хотелось бы отдельно вернуться к RTK Query - эта тема зашла хуже всего, слишком много абстракций.
Но это все позже, а далее по плану - взглянуть на альтернативы Redux.
#управлениесостоянием #отложено
В рамках темы управления состоянием мы разобрались со связкой
useContext
+ useReducer
, познакомились с Redux и даже с Redux Toolkit.В документации Redux еще осталось несколько интересных разделов (Faq, Style Guide, Api Reference), но информация в них во многом повторяется, поэтому пока можно пойти дальше, а к ним вернуться на досуге.
Кроме того, хотелось бы отдельно вернуться к RTK Query - эта тема зашла хуже всего, слишком много абстракций.
Но это все позже, а далее по плану - взглянуть на альтернативы Redux.
#управлениесостоянием #отложено
Telegram
React Junior
Управление состоянием
Разобравшись более-менее с маршрутизацией (значимых альтернатив React Router вроде не нашлось), переходим к новой большой (очень большой) теме: управление глобальным состоянием приложения.
В ее рамках планирую:
- освежить в памяти…
Разобравшись более-менее с маршрутизацией (значимых альтернатив React Router вроде не нашлось), переходим к новой большой (очень большой) теме: управление глобальным состоянием приложения.
В ее рамках планирую:
- освежить в памяти…
👍1
Recoil. Первый взгляд
Recoil - это инструмент управления глобальным состоянием приложения, созданный специально для React. Интерфейс библиотеки очевидно вдохновлен реактом, поэтому использовать ее очень просто.
Атомы
Состояние представлено в виде атомов. То есть мы не создаем единый объект для всего состояния приложения, как в Redux. А делим состояние на отдельные порции и каждую оборачиваем в функцию
Список элементов TODO-листа будет выглядить вот так:
А это значение фильтра по статусу элементов:
Селекторы
Как и в Redux, в атомах рекомендуется хранить минимально возможный объем данных без повторений. Все производное состояние (которое можно вычислить) должно вычисляться. Для этого в Recoil есть селекторы. По сути это просто чистые функции, которые подписываются на изменение атомов (или других селекторов) и пересчитывают при необходимости свое значение. У селекторов тоже должно быть уникальное имя.
Вот так выглядит вычисление отфильтрованного списка элементов:
Внутри функции селектора есть доступ к функции
Получение значений
Для получения значений атомов и селекторов есть хук
Получаем отфильтрованный список, чтобы вывести его в компоненте.
Изменение значений
Значение селектора нельзя изменить, так как оно вычисляемое. А для работы с атомами есть хук
Кроме того есть хук
Корневой элемент
Чтобы это все работало, приложение нужно обернуть в компонент
Демо
Маленькое приложение (TODO-лист), демонстрирующее основы Recoil: https://codesandbox.io/s/recoil-react-junior-3orhdl?file=/src/App.js
#управлениесостоянием #recoil #примерыкода
Recoil - это инструмент управления глобальным состоянием приложения, созданный специально для React. Интерфейс библиотеки очевидно вдохновлен реактом, поэтому использовать ее очень просто.
Атомы
Состояние представлено в виде атомов. То есть мы не создаем единый объект для всего состояния приложения, как в Redux. А делим состояние на отдельные порции и каждую оборачиваем в функцию
atom
. Каждый атом при этом должен иметь уникальное имя.Список элементов TODO-листа будет выглядить вот так:
const todoListState = atom({
key: "todoListState",
default: []
});
А это значение фильтра по статусу элементов:
const todoListFilterState = atom({
key: "todoListFilterState",
default: 'all'
});
Селекторы
Как и в Redux, в атомах рекомендуется хранить минимально возможный объем данных без повторений. Все производное состояние (которое можно вычислить) должно вычисляться. Для этого в Recoil есть селекторы. По сути это просто чистые функции, которые подписываются на изменение атомов (или других селекторов) и пересчитывают при необходимости свое значение. У селекторов тоже должно быть уникальное имя.
Вот так выглядит вычисление отфильтрованного списка элементов:
const filteredTodoListState = selector({
key: "filteredTodoListState",
get: function(get) {
const filter = get(todoListFilterState);
const todos = get(todoListState);
switch (filter) {
case 'completed':
return todos.filter(function (todo) { return todo.isComplete });
case ACTIVE:
return todos.filter(function (todo) { return !todo.isComplete });
default:
return todos;
}
}
})
Внутри функции селектора есть доступ к функции
get
, которая и обеспечивает подписку на актуальное значение атома (или другого селектора).Получение значений
Для получения значений атомов и селекторов есть хук
useRecoilValue
. Получаем отфильтрованный список, чтобы вывести его в компоненте.
const todos = useRecoilValue(filteredTodoListState);
Изменение значений
Значение селектора нельзя изменить, так как оно вычисляемое. А для работы с атомами есть хук
useRecoilState
, который работает точно так же, как useState
.
const [filter, setFilter] = useRecoilState(todoListFilterState);
Кроме того есть хук
useSetRecoilState
. Это по сути второй компонент хука useRecoilState
, возвращает только функцию для изменения состояния (атома).
const setTodos = useSetRecoilState(todoListState);
Корневой элемент
Чтобы это все работало, приложение нужно обернуть в компонент
RecoilRoot
.
import { RecoilRoot } from "recoil";
Демо
Маленькое приложение (TODO-лист), демонстрирующее основы Recoil: https://codesandbox.io/s/recoil-react-junior-3orhdl?file=/src/App.js
#управлениесостоянием #recoil #примерыкода
CodeSandbox
Recoil. React Junior - CodeSandbox
Recoil. React Junior by furrycat.web using react, react-dom, react-scripts, recoil
👍3
Recoil. Асинхронное получение данных
Селекторы Recoil могут получать данные асинхронно, для этого функция в параметре
Селекторы с параметрами
Если в запрос нужно передать параметры, которые могут изменяться (например, id пользователя), то нужно использовать не просто селектор, а "семью селекторов" - функцию
Интерфейс у нее похожий, только метод
Suspense
Компонент, который использует такой асинхронный селектор, может отрендериться раньше, чем будет выполнен запрос и получены данные. Чтобы этого не происходило, нужно обернуть этот компонент в React.Suspense https://yangx.top/react_junior/62. Recoil специально разработан для этой ситуации, поэтому React.Suspense знает, когда компонент готов к отображению, а до этого показывает фоллбэк.
Обработка ошибок
Также стоит заранее позаботиться об обработке ошибок и обернуть нужную часть приложения в ErrorBoundary (предохранитель) https://yangx.top/react_junior/54.
#управлениесостоянием #recoil #примерыкода #обработкаошибок
Селекторы Recoil могут получать данные асинхронно, для этого функция в параметре
get
должна возвращать промис (например, async функция). Такой селектор можно использовать для запроса данных с сервера.
export const currentUserNameQuery = selector({
key: "CurrentUser",
get: async function() {
const response = await getCurrentUserInfo();
if (response.error) {
throw response.error;
}
return response.name;
}
});
Селекторы с параметрами
Если в запрос нужно передать параметры, которые могут изменяться (например, id пользователя), то нужно использовать не просто селектор, а "семью селекторов" - функцию
selectorFamily
.Интерфейс у нее похожий, только метод
get
- это функция, которая принимает необходимые параметры, а вернуть должна уже нормальную функцию-селектор:
export const userNameQuery = selectorFamily({
key: "UserName",
get: function (userId) {
return async function() {
const response = await getUserInfo(userId);
if (response.error) {
throw response.error;
}
return response.name;
}
}
});
Suspense
Компонент, который использует такой асинхронный селектор, может отрендериться раньше, чем будет выполнен запрос и получены данные. Чтобы этого не происходило, нужно обернуть этот компонент в React.Suspense https://yangx.top/react_junior/62. Recoil специально разработан для этой ситуации, поэтому React.Suspense знает, когда компонент готов к отображению, а до этого показывает фоллбэк.
Обработка ошибок
Также стоит заранее позаботиться об обработке ошибок и обернуть нужную часть приложения в ErrorBoundary (предохранитель) https://yangx.top/react_junior/54.
#управлениесостоянием #recoil #примерыкода #обработкаошибок
Telegram
React Junior
Ленивые компоненты
React-компоненты можно загружать динамически, по необходимости с помощью функции import(). Для этого существует метод React.lazy, который принимает коллбэк с импортом нужного файла.
https://codesandbox.io/s/react-lazy-react-junior-6rjyv…
React-компоненты можно загружать динамически, по необходимости с помощью функции import(). Для этого существует метод React.lazy, который принимает коллбэк с импортом нужного файла.
https://codesandbox.io/s/react-lazy-react-junior-6rjyv…
👍3
Recoil. Асинхронные данные без Suspense
Работать с асинхронным состоянием можно и без React.Suspense. В Recoil для этого есть хук
Пример: https://codesandbox.io/s/recoil-userecoilvalueloadable-react-junior-0tgwh7?file=/src/components/UserInfo.js
#управлениесостоянием #recoil #примерыкода
Работать с асинхронным состоянием можно и без React.Suspense. В Recoil для этого есть хук
useRecoilValueLoadable
. Это почти то же самое, что и useRecoilValue
(и useState
), но кроме собственно значения (находится в поле contents
) есть еще статус загрузки (в поле state
). Статус может быть равен hasValue
, loading
или hasError
.const { state, contents } = useRecoilValueLoadable(userNameQuery(userId));
Пример: https://codesandbox.io/s/recoil-userecoilvalueloadable-react-junior-0tgwh7?file=/src/components/UserInfo.js
#управлениесостоянием #recoil #примерыкода
CodeSandbox
Recoil. useRecoilValueLoadable. React Junior - CodeSandbox
Recoil. useRecoilValueLoadable. React Junior by furrycat.web using react, react-dom, react-scripts, recoil
👍3
Селекторы в Recoil кешируются
Ожидается, что наши селекторы являются идемпотентными функциями, то есть для одинаковых входных данных всегда возвращают одинаковый результат. Поэтому значения селекторов кешируются. Входныхми данными при этом являются подписки селектора - атомы и другие селекторы.
Пример: https://codesandbox.io/s/recoil-cache-react-junior-198glr?file=/src/App.js
У нас есть атом
Есть селектор
Однако Recoil не выполняет запрос для того же id повторно. Получив один раз данные для пользователя
#recoil #управлениесостоянием #примерыкода #документация
Ожидается, что наши селекторы являются идемпотентными функциями, то есть для одинаковых входных данных всегда возвращают одинаковый результат. Поэтому значения селекторов кешируются. Входныхми данными при этом являются подписки селектора - атомы и другие селекторы.
Пример: https://codesandbox.io/s/recoil-cache-react-junior-198glr?file=/src/App.js
У нас есть атом
userIdState
, значение которого изменяется с помощью кнопок.Есть селектор
userDataQuery
, который получает данные пользователя по его id. У пользователя есть поле changingField
, это счетчик, значение которого увеличивается при каждом запросе. То есть два запроса с одинаковым id по идее должны вернуть разное значение changingField
.Однако Recoil не выполняет запрос для того же id повторно. Получив один раз данные для пользователя
id: 1
, он их кеширует.#recoil #управлениесостоянием #примерыкода #документация
CodeSandbox
Recoil. Cache. React Junior - CodeSandbox
Recoil. Cache. React Junior by furrycat.web using react, react-dom, react-scripts, recoil
👍3
Класс Loadable
Статья в документации (англ.): https://recoiljs.org/docs/api-reference/core/Loadable
Объекты этого класса представляют состояние атома или селектора. У них есть следующие поля:
-
-
Мы уже использовали такой Loadable-объект, его возвращает хук
Можно создать Loadable вручную, для этого нужен объект
Можно с асинхронными значениями:
У Loadable есть несколько методов, но они все пока нестабильны:
-
-
-
-
-
#recoil #управлениесостоянием #документация #примерыкода
Статья в документации (англ.): https://recoiljs.org/docs/api-reference/core/Loadable
Объекты этого класса представляют состояние атома или селектора. У них есть следующие поля:
-
state
: hasValue
, hasError
, loading
-
contents
: тут лежит либо выполняющийся промис (если loading
), либо объект выброшенной ошибки (если hasError
), либо само значение атома/селектора (если hasValue
)Мы уже использовали такой Loadable-объект, его возвращает хук
useRecoilValueLoadable
.Можно создать Loadable вручную, для этого нужен объект
RecoilLoadable
.RecoilLoadable.of(123);
RecoilLoadable.error(new Error('ERROR'));
RecoilLoadable.all([
RecoilLoadable.of(1),
RecoilLoadable.of(10),
RecoilLoadable.of(100),
]).map(([a, b, c]) => a+b+c);
Можно с асинхронными значениями:
RecoilLoadable.of('x');
RecoilLoadable.of(RecoilLoadable.of('x'));
RecoilLoadable.of(Promise.resolve('x'));
У Loadable есть несколько методов, но они все пока нестабильны:
-
getValue()
-
toPromise()
-
valueMaybe()
-
valueOrThrow()
-
map(callback)
#recoil #управлениесостоянием #документация #примерыкода
recoiljs.org
class Loadable | Recoil
A Loadable object represents the current state of a Recoil atom or selector. This state may either have a value available, may be in an error state, or may still be pending asynchronous resolution. A Loadable has the following interface:
👍1
Дефолтное значение атома
В поле
Но также здесь может быть промис, Loadable, другой атом или селектор.
Пример: https://codesandbox.io/s/brave-fermi-40n0p8?file=/src/App.js
Обращаться с таким атомом нужно точно так же, как с асинхронным селектором: либо с React.Suspense, либо с хуком useRecoilValueLoadable.
#recoil #управлениесостоянием #документация #примерыкода
В поле
default
атома можно указать просто значение (примитив/объект).Но также здесь может быть промис, Loadable, другой атом или селектор.
Пример: https://codesandbox.io/s/brave-fermi-40n0p8?file=/src/App.js
Обращаться с таким атомом нужно точно так же, как с асинхронным селектором: либо с React.Suspense, либо с хуком useRecoilValueLoadable.
#recoil #управлениесостоянием #документация #примерыкода
Telegram
React Junior
Класс Loadable
Статья в документации (англ.): https://recoiljs.org/docs/api-reference/core/Loadable
Объекты этого класса представляют состояние атома или селектора. У них есть следующие поля:
- state: hasValue, hasError, loading
- contents: тут лежит либо…
Статья в документации (англ.): https://recoiljs.org/docs/api-reference/core/Loadable
Объекты этого класса представляют состояние атома или селектора. У них есть следующие поля:
- state: hasValue, hasError, loading
- contents: тут лежит либо…
👍1
Forwarded from Cat in Web
Что не так с "Голыми промисами" и чем их заменить
Статья (англ.): https://www.freecodecamp.org/news/naked-promises-are-not-safe-for-work/
Эта тема довольно часто поднимается в статьях: промисы в чистом виде не очень удобны.
Во-первых, их нельзя отменить (вообще можно, но это требует некоторого объема дополнительного кода).
Во-вторых, вызов промиса создает сразу несколько состояний, которые обычно нужно отслеживать (состояние загрузки, возможная ошибка выполнения).
Кроме того в некоторых случаях при выполнении промиса требуется проверить, актуален ли контекст его выполнения (например, не размонтирован ли к этому времени компонент React).
В качестве решения проблемы автор предлагает просто обернуть промис, инкапсулировав всю дополнительную логику, и предлагает сразу несколько готовых пакетов (react-async, react-use, react-hooks-async).
#react #promise #patterns
Статья (англ.): https://www.freecodecamp.org/news/naked-promises-are-not-safe-for-work/
Эта тема довольно часто поднимается в статьях: промисы в чистом виде не очень удобны.
Во-первых, их нельзя отменить (вообще можно, но это требует некоторого объема дополнительного кода).
Во-вторых, вызов промиса создает сразу несколько состояний, которые обычно нужно отслеживать (состояние загрузки, возможная ошибка выполнения).
Кроме того в некоторых случаях при выполнении промиса требуется проверить, актуален ли контекст его выполнения (например, не размонтирован ли к этому времени компонент React).
В качестве решения проблемы автор предлагает просто обернуть промис, инкапсулировав всю дополнительную логику, и предлагает сразу несколько готовых пакетов (react-async, react-use, react-hooks-async).
#react #promise #patterns
freeCodeCamp.org
Why Naked Promises Are Not Safe For Work - and What to Do Instead
This article goes through my personal journey of discovery and struggle adopting the conventional wisdom as it pertains to asynchronous work on the frontend. With any luck, you will come away with at least a deeper appreciation of 3 tricky cases to handle…
👍1
atomFamily и selectorFamily
Это две полезные утилиты, которые позволяют создавать коллекции атомов или селекторов. Утилите нужно передать параметр, который по сути станет идентификатором значения.
При передаче разных параметров вернутся разные (разные экземпляры) атомы/селекторы, при передаче одного - один (причем даже в разных частях приложения).
Параметр при этом можно использовать.
Например, для определения дефолтного значения атома при создании:
Создаем с помощью
#recoil #управлениесостоянием #документация #примерыкода
Это две полезные утилиты, которые позволяют создавать коллекции атомов или селекторов. Утилите нужно передать параметр, который по сути станет идентификатором значения.
При передаче разных параметров вернутся разные (разные экземпляры) атомы/селекторы, при передаче одного - один (причем даже в разных частях приложения).
Параметр при этом можно использовать.
Например, для определения дефолтного значения атома при создании:
const myAtomFamily = atomFamily({Или (как мы уже делали) как параметр запроса внутри селектора:
key: 'MyAtom',
default: function(param) {
return `atom-${param}`;
}
})
const mySelectorFamily = selectorFamily({Пример: https://codesandbox.io/s/recoil-atomfamily-react-junior-bj84yl
key: 'MySelector',
get: function(param) {
return async function() {
const response = await fetch(`/get-data?id=${param}`);
return response;
}
}
})
Создаем с помощью
myAtomFamily
два атома с разными параметрами (1 и 2). Их можно использовать и изменять отдельно. По этому параметру их можно получить в другом компоненте, при этом значение будет синхронизировано.#recoil #управлениесостоянием #документация #примерыкода
Telegram
React Junior
Recoil. Асинхронное получение данных
Селекторы Recoil могут получать данные асинхронно, для этого функция в параметре get должна возвращать промис (например, async функция). Такой селектор можно использовать для запроса данных с сервера.
export const …
Селекторы Recoil могут получать данные асинхронно, для этого функция в параметре get должна возвращать промис (например, async функция). Такой селектор можно использовать для запроса данных с сервера.
export const …
👍1