Плюсы useEffect
☑️ Не нужно дублировать одну и ту же логику в componentDidMount и componentDidUpdate. useEffect вызывается после каждого рендера, включая самый первый.
☑️ Можно инкапсулировать всю связанную логику в одном месте, не разделяя, например, установку подписки в componentDidMount и ее сброс в componentWillUnmount.
☑️ Проще установить связь эффекта с конкретными пропсами или полями состояния - нужно просто передать в useEffect массив, а не сравнивать вручную (как в componentDidUpdate).
#документация #хуки
☑️ Не нужно дублировать одну и ту же логику в componentDidMount и componentDidUpdate. useEffect вызывается после каждого рендера, включая самый первый.
☑️ Можно инкапсулировать всю связанную логику в одном месте, не разделяя, например, установку подписки в componentDidMount и ее сброс в componentWillUnmount.
☑️ Проще установить связь эффекта с конкретными пропсами или полями состояния - нужно просто передать в useEffect массив, а не сравнивать вручную (как в componentDidUpdate).
#документация #хуки
Telegram
React Junior
componentDidMount
Метод вызывается сразу после монтирования компонента в DOM.
Особенности работы
👉 В методе допустимо вызывать setState(), что сразу же вызовет дополнительный рендер. При этом промежуточное состояние пользователь не увидит. Это может быть…
Метод вызывается сразу после монтирования компонента в DOM.
Особенности работы
👉 В методе допустимо вызывать setState(), что сразу же вызовет дополнительный рендер. При этом промежуточное состояние пользователь не увидит. Это может быть…
Пользовательские хуки
Пользовательские хуки - это обычные функции, внутри которых можно вызывать другие хуки (встроенные - useState, useEffect). React настойчиво рекомендует, чтобы название пользовательских хуков начиналось с use. Пользовательские хуки нужны исключительно для удобства, чтобы не писать одну и ту же логику внутри компонента, а вынести ее отдельно - для удобного тестирования и переиспользования.
Механизм действия точно такой же, как если бы все происходило внутри компонента - хуки записываются в порядке вызова в ячейки памяти компонента, который рендерится в данный момент.
Основная идея встроенных хуков - дать функциональным компонентам возможности классовых (состояние, методы жизненного цикла)ж
Основная идея пользовательских хуков - инкапсуляция некоторой логики для упрощения кода и повторного использования.
Для уяснения этого попробуем реализовать одну и ту же задачу с хуками и без них.
Задача: брокерское приложение
Есть API для подписки на изменение цены биржевых акций. Есть список акций и детальное представление каждой акции. И превью акции внутри общего списка, и детальное представление акции должны отображать актуальную цену этой акции. То есть компонент при создании должен подписаться на изменение цены, сохранить цену в своем состоянии, вывести ее, а также не забыть отписаться при размонтировании. Также нужно учитывать, что если в компонент передается другой тикер акции, от предыдущего нужно отписаться, а на новый подписаться.
Основная цель: абстрагирование логики подписки/отписки на цену.
В следующих постах попробуем решить эту задачу сначала без хуков, а потом с ними.
👉 решение с помощью компонентов высшего порядка
👉 решение с помощью рендер-пропсов
👉 решение с помощью хуков
#документация #хуки
Пользовательские хуки - это обычные функции, внутри которых можно вызывать другие хуки (встроенные - useState, useEffect). React настойчиво рекомендует, чтобы название пользовательских хуков начиналось с use. Пользовательские хуки нужны исключительно для удобства, чтобы не писать одну и ту же логику внутри компонента, а вынести ее отдельно - для удобного тестирования и переиспользования.
Механизм действия точно такой же, как если бы все происходило внутри компонента - хуки записываются в порядке вызова в ячейки памяти компонента, который рендерится в данный момент.
Основная идея встроенных хуков - дать функциональным компонентам возможности классовых (состояние, методы жизненного цикла)ж
Основная идея пользовательских хуков - инкапсуляция некоторой логики для упрощения кода и повторного использования.
Для уяснения этого попробуем реализовать одну и ту же задачу с хуками и без них.
Задача: брокерское приложение
Есть API для подписки на изменение цены биржевых акций. Есть список акций и детальное представление каждой акции. И превью акции внутри общего списка, и детальное представление акции должны отображать актуальную цену этой акции. То есть компонент при создании должен подписаться на изменение цены, сохранить цену в своем состоянии, вывести ее, а также не забыть отписаться при размонтировании. Также нужно учитывать, что если в компонент передается другой тикер акции, от предыдущего нужно отписаться, а на новый подписаться.
Основная цель: абстрагирование логики подписки/отписки на цену.
В следующих постах попробуем решить эту задачу сначала без хуков, а потом с ними.
👉 решение с помощью компонентов высшего порядка
👉 решение с помощью рендер-пропсов
👉 решение с помощью хуков
#документация #хуки
Telegram
React Junior
Инкапсуляция логики без хуков: компоненты высшего порядка
Чтобы инкапсулировать некоторую логику, мы можем использовать компоненты высшего порядка. Проще говоря, мы можем создать обертку с нужной логикой, а затем передавать в нее содержимое (основной компонент).…
Чтобы инкапсулировать некоторую логику, мы можем использовать компоненты высшего порядка. Проще говоря, мы можем создать обертку с нужной логикой, а затем передавать в нее содержимое (основной компонент).…
Инкапсуляция логики без хуков: компоненты высшего порядка
Задача: Брокерское приложение
Чтобы инкапсулировать некоторую логику, мы можем использовать компоненты высшего порядка. Проще говоря, мы можем создать обертку с нужной логикой, а затем передавать в нее содержимое (основной компонент).
https://codesandbox.io/s/broker-app-hoc-react-junior-lh6h9?file=/src/App.js
Основные моменты
У нас есть компонент высшего порядка Watcher, который
1. реализует логику подписки при монтировании (componentDidMount) и отписки при размонтировании (componentWillUnmount);
2. при изменении тикера акции отписывается от предыдущего и подписывается на новый (componentDidUpdate);
3. рендерит переданный ему компонент, которому передает все исходные пропсы, а также дополнительный проп price - актуальная цена акции.
Мы можем завернуть в этот HOC и превью акции в списке (компонент SecurityPreview), и детальное представление акции (компонент SecurityView). Задача выполнена - логика абстрагирована.
#примерыкода #hoc
Задача: Брокерское приложение
Чтобы инкапсулировать некоторую логику, мы можем использовать компоненты высшего порядка. Проще говоря, мы можем создать обертку с нужной логикой, а затем передавать в нее содержимое (основной компонент).
https://codesandbox.io/s/broker-app-hoc-react-junior-lh6h9?file=/src/App.js
Основные моменты
У нас есть компонент высшего порядка Watcher, который
1. реализует логику подписки при монтировании (componentDidMount) и отписки при размонтировании (componentWillUnmount);
2. при изменении тикера акции отписывается от предыдущего и подписывается на новый (componentDidUpdate);
3. рендерит переданный ему компонент, которому передает все исходные пропсы, а также дополнительный проп price - актуальная цена акции.
Мы можем завернуть в этот HOC и превью акции в списке (компонент SecurityPreview), и детальное представление акции (компонент SecurityView). Задача выполнена - логика абстрагирована.
#примерыкода #hoc
Telegram
React Junior
Пользовательские хуки
Пользовательские хуки - это обычные функции, внутри которых можно вызывать другие хуки (встроенные - useState, useEffect). React настойчиво рекомендует, чтобы название пользовательских хуков начиналось с use. Пользовательские хуки нужны…
Пользовательские хуки - это обычные функции, внутри которых можно вызывать другие хуки (встроенные - useState, useEffect). React настойчиво рекомендует, чтобы название пользовательских хуков начиналось с use. Пользовательские хуки нужны…
Инкапсуляция логики без хуков: рендер-пропсы
Задача: Брокерское приложение
Подход с рендер-пропсами очень похож на предыдущий, с компонентами высшего порядка. По крайней мере, суть такая же - логика инкапсулируется в обертке.
Есть некая обертка (отдельный компонент), которая знает, что делать (подписываться и отписываться). Она получает основной компонент и вкладывает его в себя, передавая ему свое знание. По сути это декоратор.
Рендер-пропсы отлично подходят, если помимо логики требуется инкапсулировать еще какую-то часть разметки. Например, можно вывести актуальную цену в верхнем углу блока.
https://codesandbox.io/s/broker-app-render-props-react-junior-f82n5?file=/src/App.js
Основные компоненты не изменились. Но теперь мы не оборачиваем SecurityPreview и SecurityView в вызов Watcher, а выводим в нужном месте компонент-обертку Price, которому передаем проп render - функцию, которая генерирует нужную разметку. Price выполнит все действия по подписке, отрендерит текущую цену и затем выполнит вызов пропа render, чтобы получить остальную разметку.
Обратите внимание, проп может называться как угодно, просто слово render максимально подходит к логике действия.
#примерыкода #рендерпропсы
Задача: Брокерское приложение
Подход с рендер-пропсами очень похож на предыдущий, с компонентами высшего порядка. По крайней мере, суть такая же - логика инкапсулируется в обертке.
Есть некая обертка (отдельный компонент), которая знает, что делать (подписываться и отписываться). Она получает основной компонент и вкладывает его в себя, передавая ему свое знание. По сути это декоратор.
Рендер-пропсы отлично подходят, если помимо логики требуется инкапсулировать еще какую-то часть разметки. Например, можно вывести актуальную цену в верхнем углу блока.
https://codesandbox.io/s/broker-app-render-props-react-junior-f82n5?file=/src/App.js
Основные компоненты не изменились. Но теперь мы не оборачиваем SecurityPreview и SecurityView в вызов Watcher, а выводим в нужном месте компонент-обертку Price, которому передаем проп render - функцию, которая генерирует нужную разметку. Price выполнит все действия по подписке, отрендерит текущую цену и затем выполнит вызов пропа render, чтобы получить остальную разметку.
Обратите внимание, проп может называться как угодно, просто слово render максимально подходит к логике действия.
#примерыкода #рендерпропсы
Telegram
React Junior
Пользовательские хуки
Пользовательские хуки - это обычные функции, внутри которых можно вызывать другие хуки (встроенные - useState, useEffect). React настойчиво рекомендует, чтобы название пользовательских хуков начиналось с use. Пользовательские хуки нужны…
Пользовательские хуки - это обычные функции, внутри которых можно вызывать другие хуки (встроенные - useState, useEffect). React настойчиво рекомендует, чтобы название пользовательских хуков начиналось с use. Пользовательские хуки нужны…
Инкапсуляция логики с пользовательскими хуками
Задача: Брокерское приложение
Хуки предлагают совершенно иной подход к инкапсуляции логики в приложении. Если с компонентами высшего порядка и рендер-пропсами мы помещали логику в обертку, то есть по сути создавали дополнительный родительский компонент, то хуки позволяют подключать логику как часть исходного компонента (простой композицией). Мы передаем нужную логику, а не нужный компонент.
https://codesandbox.io/s/broker-app-hooks-react-junior-hsgrt
Теперь логика подписки/отписки переместилась туда, где ей и место - в сами компоненты SecurityView и SecurityPreview. Мы вынесли ее в отдельную функцию usePrice, внутри которой используем встроенные хуки useState (для хранения цены) и useEffect (для взаимодействия с апи).
usePrice - это и есть пользовательский хук. Не то чтобы это был именно хук - простая функция, но очень похож по интерфейсу, поэтому так и называется. Пользовательские хуки - это соглашение, соответствующее дизайну встроенных хуков.
#примерыкода #хуки
Задача: Брокерское приложение
Хуки предлагают совершенно иной подход к инкапсуляции логики в приложении. Если с компонентами высшего порядка и рендер-пропсами мы помещали логику в обертку, то есть по сути создавали дополнительный родительский компонент, то хуки позволяют подключать логику как часть исходного компонента (простой композицией). Мы передаем нужную логику, а не нужный компонент.
https://codesandbox.io/s/broker-app-hooks-react-junior-hsgrt
Теперь логика подписки/отписки переместилась туда, где ей и место - в сами компоненты SecurityView и SecurityPreview. Мы вынесли ее в отдельную функцию usePrice, внутри которой используем встроенные хуки useState (для хранения цены) и useEffect (для взаимодействия с апи).
usePrice - это и есть пользовательский хук. Не то чтобы это был именно хук - простая функция, но очень похож по интерфейсу, поэтому так и называется. Пользовательские хуки - это соглашение, соответствующее дизайну встроенных хуков.
#примерыкода #хуки
Telegram
React Junior
Пользовательские хуки
Пользовательские хуки - это обычные функции, внутри которых можно вызывать другие хуки (встроенные - useState, useEffect). React настойчиво рекомендует, чтобы название пользовательских хуков начиналось с use. Пользовательские хуки нужны…
Пользовательские хуки - это обычные функции, внутри которых можно вызывать другие хуки (встроенные - useState, useEffect). React настойчиво рекомендует, чтобы название пользовательских хуков начиналось с use. Пользовательские хуки нужны…
useState
Сигнатура: const [state, setState] = useState(initialState);
(названия state и setState могут быть любыми)
- state - актуальное состояние
- setState - метод для обновления состояния state
Обновление состояния с помощью setState приводит к перерендеру компонента (если новое состояние отличается от старого).
Метод setState должен возвращать новое состояние полностью (this.setState у классовых компонентов мог вернуть только обновленные поля, которые автоматически объединялись с объектом текущего состояния).
setState может принимать как просто новое значение, так и функцию. Аргументом в эту функцию будет передано текущее состояние. Все в точности как с функциональным вариантом this.setState у классовых компонентов.
Подробнее про хук состояния: https://yangx.top/react_junior/98
#документация #хуки
Сигнатура: const [state, setState] = useState(initialState);
(названия state и setState могут быть любыми)
- state - актуальное состояние
- setState - метод для обновления состояния state
Обновление состояния с помощью setState приводит к перерендеру компонента (если новое состояние отличается от старого).
Метод setState должен возвращать новое состояние полностью (this.setState у классовых компонентов мог вернуть только обновленные поля, которые автоматически объединялись с объектом текущего состояния).
setState может принимать как просто новое значение, так и функцию. Аргументом в эту функцию будет передано текущее состояние. Все в точности как с функциональным вариантом this.setState у классовых компонентов.
Подробнее про хук состояния: https://yangx.top/react_junior/98
#документация #хуки
useEffect
Сигнатура: useEffect(didUpdate, values);
- didUpdate - это функция, которая содержит императивный код, возможно с побочными эффектами. Будет вызываться после каждого рендера компонента - после того, как результат рендера будет зафиксирован на экране.
didUpdate может вернуть функцию для сброса эффекта.
- values - необязательный аргумент, массив переменных, при изменении которых будет вызван эффект. Используется для условного выполнения эффектов.
Важно
При использовании условной оптимизации необходимо включить в массив все переменные, которые отслеживаются и используются эффектом, иначе он будет ссылаться на старые значения из предыдущего рендера.
Подробнее про хук эффекта: https://yangx.top/react_junior/100
#документация #хуки #важно
Сигнатура: useEffect(didUpdate, values);
- didUpdate - это функция, которая содержит императивный код, возможно с побочными эффектами. Будет вызываться после каждого рендера компонента - после того, как результат рендера будет зафиксирован на экране.
didUpdate может вернуть функцию для сброса эффекта.
- values - необязательный аргумент, массив переменных, при изменении которых будет вызван эффект. Используется для условного выполнения эффектов.
Важно
При использовании условной оптимизации необходимо включить в массив все переменные, которые отслеживаются и используются эффектом, иначе он будет ссылаться на старые значения из предыдущего рендера.
Подробнее про хук эффекта: https://yangx.top/react_junior/100
#документация #хуки #важно
useContext
Понятие контекста aka глобальных переменных в React мы уже разбирали - https://yangx.top/react_junior/58.
В классовых компонентах, чтобы подписаться на контекст нужно было определить статическое свойство класса contextType и записать туда объект контекста, созданный функцией React.createContext.
Второй вариант - воспользоваться компонентом Context.Consumer, который вместо внутренней разметки принимает рендер-функцию.
Для функциональных же компонентов React предоставляет хук useContext.
Сигнатура: const value = useContext(MyContext);
- MyContext - объект контекста
- value - актуальное значение контекста
Все остальное не меняется: по-прежнему нужен Context.Provider, чтобы предоставить значение контекста во все нижележащие компоненты.
#документация #хуки #контекст
Понятие контекста aka глобальных переменных в React мы уже разбирали - https://yangx.top/react_junior/58.
В классовых компонентах, чтобы подписаться на контекст нужно было определить статическое свойство класса contextType и записать туда объект контекста, созданный функцией React.createContext.
Второй вариант - воспользоваться компонентом Context.Consumer, который вместо внутренней разметки принимает рендер-функцию.
Для функциональных же компонентов React предоставляет хук useContext.
Сигнатура: const value = useContext(MyContext);
- MyContext - объект контекста
- value - актуальное значение контекста
Все остальное не меняется: по-прежнему нужен Context.Provider, чтобы предоставить значение контекста во все нижележащие компоненты.
#документация #хуки #контекст
Telegram
React Junior
Контекст
Контекст - это "глобальные переменные" React.
По умолчанию, чтобы глубоко дочерний компонент получил какую-то важную информацию, определенную на верхнем уровне, ее нужно пробросить до него по цепочке пропсов. Но иногда это излишне, особенно если…
Контекст - это "глобальные переменные" React.
По умолчанию, чтобы глубоко дочерний компонент получил какую-то важную информацию, определенную на верхнем уровне, ее нужно пробросить до него по цепочке пропсов. Но иногда это излишне, особенно если…
useReducer
Альтернатива useState для более сложной логики состояния.
Сигнатура: const [state, dispatch] = useReducer(reducer, initialArg, init);
- reducer - функция с сигнатурой (state, action) => newState, которая должна вернуть актуальное состояние
- initialArg - начальное состояние
- init - функция для ленивой инициализации, получает initialArg в качестве аргумента
- dispatch - метод для изменения состояния по модели событий
Вкратце это работает так:
1. Вызываем хук, передаем ему функцию-редьюсер и начальное состояние любым удобным способом (или inialtArg, или результат init).
2. Когда нужно изменить состояние вызываем метод dispatch с аргументом вида { type, payload }. Другими словами, эмитируем событие с типом type и полезной нагрузкой (необязательно).
3. Это событие передается в редьюсер, который должен преобразовать состояние и вернуть уже обновленное.
Подробнее о редьюсерах мы узнаем, когда будем разбираться с Redux. Но в целом это выглядит как более сложный useState, основанный на модели событий.
#документация #хуки #примерыкода
Альтернатива useState для более сложной логики состояния.
Сигнатура: const [state, dispatch] = useReducer(reducer, initialArg, init);
- reducer - функция с сигнатурой (state, action) => newState, которая должна вернуть актуальное состояние
- initialArg - начальное состояние
- init - функция для ленивой инициализации, получает initialArg в качестве аргумента
- dispatch - метод для изменения состояния по модели событий
Вкратце это работает так:
1. Вызываем хук, передаем ему функцию-редьюсер и начальное состояние любым удобным способом (или inialtArg, или результат init).
2. Когда нужно изменить состояние вызываем метод dispatch с аргументом вида { type, payload }. Другими словами, эмитируем событие с типом type и полезной нагрузкой (необязательно).
3. Это событие передается в редьюсер, который должен преобразовать состояние и вернуть уже обновленное.
Подробнее о редьюсерах мы узнаем, когда будем разбираться с Redux. Но в целом это выглядит как более сложный useState, основанный на модели событий.
#документация #хуки #примерыкода
useMemo
Хук useMemo получает функцию и массив зависимостей и возвращает результат выполнения этой функции. При следующих рендерах этот результат будет пересчитан только если одна из зависимостей изменится.
Другими словами, хук useMemo помогает избежать повторного выполнения функции внутри компонента без необходимости.
Если массив зависимостей не передан, то значение будет вычисляться при каждом рендере.
Важно
Функция, переданная useMemo, выполняется во время рендеринга, то есть она не должна вызывать побочные эффекты - для этого есть useEffect.
#хуки #документация #оптимизация
Хук useMemo получает функцию и массив зависимостей и возвращает результат выполнения этой функции. При следующих рендерах этот результат будет пересчитан только если одна из зависимостей изменится.
Другими словами, хук useMemo помогает избежать повторного выполнения функции внутри компонента без необходимости.
Если массив зависимостей не передан, то значение будет вычисляться при каждом рендере.
Важно
Функция, переданная useMemo, выполняется во время рендеринга, то есть она не должна вызывать побочные эффекты - для этого есть useEffect.
#хуки #документация #оптимизация
useCallback
Хук useCallback очень похож на useMemo, только работает не со значениями, а с коллбэками. По сути это то же самое, как если бы вы передали в useMemo функцию.
Полученную из useCallback функцию-коллбэк можно передать дочерним компонентам с уверенностью, что она не изменится в следующем рендере.
#оптимизация #документация #хуки
Хук useCallback очень похож на useMemo, только работает не со значениями, а с коллбэками. По сути это то же самое, как если бы вы передали в useMemo функцию.
Полученную из useCallback функцию-коллбэк можно передать дочерним компонентам с уверенностью, что она не изменится в следующем рендере.
#оптимизация #документация #хуки
useRef
Сигнатура: const refContainer = useRef(initialValue);
- refContainer - объект со свойством current. refContainer не меняется в течение всего времени жизни компонента, а вот current вполне может мутировать.
Иначе говоря, ref - это неизменяющийся контейнер для изменяющегося значения.
Самое очевидное применение - по аналогии с рефами в классовых компонентах. Там мы использовали для создания ссылки метод React.createRef.
Но этот хук можно использовать для хранения любого мутируемого значения, по аналогии с полями экземпляра класса.
Если мы просто создадим объект с полем current внутри функционального компонента, то при каждом рендере он будет меняться (будет создаваться новый объект). useRef же возвращает один и тот же объект-контейнер.
Важно: Изменение поля current НЕ вызывает повторный рендер компонента.
#документация #хуки #рефы
Сигнатура: const refContainer = useRef(initialValue);
- refContainer - объект со свойством current. refContainer не меняется в течение всего времени жизни компонента, а вот current вполне может мутировать.
Иначе говоря, ref - это неизменяющийся контейнер для изменяющегося значения.
Самое очевидное применение - по аналогии с рефами в классовых компонентах. Там мы использовали для создания ссылки метод React.createRef.
Но этот хук можно использовать для хранения любого мутируемого значения, по аналогии с полями экземпляра класса.
Если мы просто создадим объект с полем current внутри функционального компонента, то при каждом рендере он будет меняться (будет создаваться новый объект). useRef же возвращает один и тот же объект-контейнер.
Важно: Изменение поля current НЕ вызывает повторный рендер компонента.
#документация #хуки #рефы
Telegram
React Junior
Рефы
Реф - это прямая ссылка на компонент или на DOM-элемент. Обычно рефы используются для прямого управления DOM-элементами. React обычно не одобряет такой подход, но в некоторых ситуациях он оправдан:
- Управление фокусом, выделение текста или воспроизведение…
Реф - это прямая ссылка на компонент или на DOM-элемент. Обычно рефы используются для прямого управления DOM-элементами. React обычно не одобряет такой подход, но в некоторых ситуациях он оправдан:
- Управление фокусом, выделение текста или воспроизведение…
useImperativeHandle
Помните метод React.forwardRef?
Он позволял создать компонент, который не присваивал значение атрибута ref себе, а пробрасывал его вглубь своей разметки, например, устанавливал непосредственно на поле ввода.
Другими словами, родительский компонент ставил ref на компонент-обертку, а получал DOM-элемент input, с которым мог взаимодействовать.
Хук useImperativeHandle позволяет настроить, что именно получит родительский компонент, то есть представление для рефа. Например, вместо DOM-элемента он может получить объект с методом focus. Это позволяет инкапсулировать работу с DOM-деревом.
Сигнатура: useImperativeHandle(ref, createHandle, [deps])
- ref - это объект, полученный из хука useRef.
- createHandle - функция, которая должна вернуть представление для рефа (объект с методом focus)
Пример кода - в прикрепленном скриншоте
#документация #хуки #рефы
Помните метод React.forwardRef?
Он позволял создать компонент, который не присваивал значение атрибута ref себе, а пробрасывал его вглубь своей разметки, например, устанавливал непосредственно на поле ввода.
Другими словами, родительский компонент ставил ref на компонент-обертку, а получал DOM-элемент input, с которым мог взаимодействовать.
Хук useImperativeHandle позволяет настроить, что именно получит родительский компонент, то есть представление для рефа. Например, вместо DOM-элемента он может получить объект с методом focus. Это позволяет инкапсулировать работу с DOM-деревом.
Сигнатура: useImperativeHandle(ref, createHandle, [deps])
- ref - это объект, полученный из хука useRef.
- createHandle - функция, которая должна вернуть представление для рефа (объект с методом focus)
Пример кода - в прикрепленном скриншоте
#документация #хуки #рефы
useLayoutEffect
Вариация useEffect, которая дает шанс вмешаться в рендеринг компонента.
useLayoutEffect запускается СИНХРОННО после всех изменений DOM, ДО ТОГО, как браузер осуществит их отрисовку. Это практически полный аналог классовых методов componentDidMount/componentDidUpdate.
Этот хук дает возможность что-то изменить в отрисованном представлении так, чтобы пользователь не увидел предыдущего состояния.
#документация #хуки
Вариация useEffect, которая дает шанс вмешаться в рендеринг компонента.
useLayoutEffect запускается СИНХРОННО после всех изменений DOM, ДО ТОГО, как браузер осуществит их отрисовку. Это практически полный аналог классовых методов componentDidMount/componentDidUpdate.
Этот хук дает возможность что-то изменить в отрисованном представлении так, чтобы пользователь не увидел предыдущего состояния.
#документация #хуки
useDebugValue
Позволяет отобразить метку для пользовательских хуков в React Dev Tools, что может быть полезно для дебаггинга.
#документация #хуки #отладка
Позволяет отобразить метку для пользовательских хуков в React Dev Tools, что может быть полезно для дебаггинга.
#документация #хуки #отладка
Объяснение хуков
Статья от создателя React Дэна Абрамова (англ.): https://medium.com/@dan_abramov/making-sense-of-react-hooks-fdbde8803889
В принципе все, что он говорит, мы уже рассмотрели и в целом уяснили, но все-таки пропускать статью от основателя было бы неправильно.
Основные моменты:
- До появления хуков React позволял удобно разделять UI, но не логику. Хуки решают эту проблему без добавления дополнительных оберток.
- Добавление хуков не раздувает библиотеку. Напротив, их использование позволяет уменьшить размер бандла, так как хуки минифицируются лучше, чем классы.
- Хуки больше соответствуют философии React, чем классы, но от поддержки классов никто не отказывается, ничего переписывать не нужно.
- Никакой магии в хуках нет, они не сложнее, чем Array.push/Array.pop.
- Правила хуков хоть и выглядят несколько странно, но никак не помешают в работе.
#ссылки #хуки
Статья от создателя React Дэна Абрамова (англ.): https://medium.com/@dan_abramov/making-sense-of-react-hooks-fdbde8803889
В принципе все, что он говорит, мы уже рассмотрели и в целом уяснили, но все-таки пропускать статью от основателя было бы неправильно.
Основные моменты:
- До появления хуков React позволял удобно разделять UI, но не логику. Хуки решают эту проблему без добавления дополнительных оберток.
- Добавление хуков не раздувает библиотеку. Напротив, их использование позволяет уменьшить размер бандла, так как хуки минифицируются лучше, чем классы.
- Хуки больше соответствуют философии React, чем классы, но от поддержки классов никто не отказывается, ничего переписывать не нужно.
- Никакой магии в хуках нет, они не сложнее, чем Array.push/Array.pop.
- Правила хуков хоть и выглядят несколько странно, но никак не помешают в работе.
#ссылки #хуки
Medium
Making Sense of React Hooks
This week, Sophie Alpert and I presented the “Hooks” proposal at React Conf, followed by a deep dive from Ryan Florence:
React-хуки - это не магия, а обычные массивы
Статья Rudi Yardley (англ.): https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e
Руди рассказывает о том, как примерно реализованы хуки в React, и почему мы должны соблюдать правила хуков. Вкратце мы уже это разбирали, но статью все равно стоит посмотреть, в ней есть наглядная визуализация всего механизма.
#ссылки #хуки
Статья Rudi Yardley (англ.): https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e
Руди рассказывает о том, как примерно реализованы хуки в React, и почему мы должны соблюдать правила хуков. Вкратце мы уже это разбирали, но статью все равно стоит посмотреть, в ней есть наглядная визуализация всего механизма.
#ссылки #хуки
Medium
React hooks: not magic, just arrays
Untangling the rules around the proposal using diagrams
Пример запроса данных с помощью хуков
Демо-пример: https://codesandbox.io/s/jvvkoo8pq3?file=/src/index.js
Тут все очень просто:
- Создается состояние data для массива результатов, изначально - пустой массив (хук useState)
- Создается состояние query для текста поискового запроса (хук useState)
- При изменении запроса (setQuery) происходит перерендер компонента - После рендера вызывается эффект, заданный с помощью хука useEffect (у него в зависимостях указана переменная query, значение которой изменилось, поэтому он вызывается)
- Функция-эффект запрашивает данные по апи, а когда приходит ответ, записывает его в состояние data (setData)
- Снова происходит перерендер, но в этот раз эффект не вызывается, так как его единственная зависимость query не изменилась
Пошаговый туториал: https://www.robinwieruch.de/react-hooks-fetch-data
Здесь все подробно разобрано:
- Почему в useEffect нельзя передавать асинхронную функцию
- Зачем нужен массив зависимостей и как он работает
- Зачем используется переменная ignore внутри эффекта (спойлер: чтобы не выводить данные предыдущего запроса, если после него уже отправлен новый)
- Добавление индикатора загрузки
- Обработка ошибок загрузки
- Добавление формы (form) и обработка события onSubmit
Кроме того описан пользовательский хук для извлечения данных useDataApi. Он принимает полный урл запроса, поэтому может работать с любым API. Этот хук инкапсулирует логику запроса данных, индикатора загрузки и обработки ошибок запроса.
Хук useDataApi на гитхабе: https://github.com/the-road-to-learn-react/use-data-api
Наконец в конце рассматривается кейс с заменой отдельных простых состояний (isError, isLoading, data) на единое сложное состояние с использованием хука useReducer. При этом в нужные моменты вызываются нужные события (FETCH_INIT, FETCH_SUCCESS, FETCH_FAILURE) с помощью метода dispatch, а редьюсер обрабатывает их и обновляет состояние.
#ссылки #хуки #примерыкода
Демо-пример: https://codesandbox.io/s/jvvkoo8pq3?file=/src/index.js
Тут все очень просто:
- Создается состояние data для массива результатов, изначально - пустой массив (хук useState)
- Создается состояние query для текста поискового запроса (хук useState)
- При изменении запроса (setQuery) происходит перерендер компонента - После рендера вызывается эффект, заданный с помощью хука useEffect (у него в зависимостях указана переменная query, значение которой изменилось, поэтому он вызывается)
- Функция-эффект запрашивает данные по апи, а когда приходит ответ, записывает его в состояние data (setData)
- Снова происходит перерендер, но в этот раз эффект не вызывается, так как его единственная зависимость query не изменилась
Пошаговый туториал: https://www.robinwieruch.de/react-hooks-fetch-data
Здесь все подробно разобрано:
- Почему в useEffect нельзя передавать асинхронную функцию
- Зачем нужен массив зависимостей и как он работает
- Зачем используется переменная ignore внутри эффекта (спойлер: чтобы не выводить данные предыдущего запроса, если после него уже отправлен новый)
- Добавление индикатора загрузки
- Обработка ошибок загрузки
- Добавление формы (form) и обработка события onSubmit
Кроме того описан пользовательский хук для извлечения данных useDataApi. Он принимает полный урл запроса, поэтому может работать с любым API. Этот хук инкапсулирует логику запроса данных, индикатора загрузки и обработки ошибок запроса.
Хук useDataApi на гитхабе: https://github.com/the-road-to-learn-react/use-data-api
Наконец в конце рассматривается кейс с заменой отдельных простых состояний (isError, isLoading, data) на единое сложное состояние с использованием хука useReducer. При этом в нужные моменты вызываются нужные события (FETCH_INIT, FETCH_SUCCESS, FETCH_FAILURE) с помощью метода dispatch, а редьюсер обрабатывает их и обновляет состояние.
#ссылки #хуки #примерыкода
CodeSandbox
zxn70rnkx - CodeSandbox
zxn70rnkx by gaearon using react, react-dom, react-scripts
Коллбэк-рефы в функциональных компонентах
Мы уже говорили о коллбэк-рефах здесь https://yangx.top/react_junior/42.
В двух словах: если в атрибут ref элемента передать функцию (вместо объекта, созданного методом React.createRef), она будет вызвана при монтировании этого элемента, а в качестве аргумента получит ссылку на него.
В функциональных компонентах так тоже можно делать, с одним условием - функция (коллбэк-реф) должна быть создана с помощью хука useCallback. В ином случае она будет меняться при каждом рендере.
#рефы #примерыкода #документация #хуки
Мы уже говорили о коллбэк-рефах здесь https://yangx.top/react_junior/42.
В двух словах: если в атрибут ref элемента передать функцию (вместо объекта, созданного методом React.createRef), она будет вызвана при монтировании этого элемента, а в качестве аргумента получит ссылку на него.
В функциональных компонентах так тоже можно делать, с одним условием - функция (коллбэк-реф) должна быть создана с помощью хука useCallback. В ином случае она будет меняться при каждом рендере.
#рефы #примерыкода #документация #хуки
Функции в списке зависимостей
Если мы указываем для хука список зависимостей (useEffect, useLayoutEffect, useMemo, useCallback, useImperativeHandle), в него должны войти все использованные значения, которые задействованы в потоке данных React, включая пропсы, состояние и их производные.
А что если одно из этих значений функция - внешняя по отношению к вызову хука? Нужно ли ее указывать в зависимостях к хуку useEffect. (см. прикрепленный скриншот)
С одной стороны - да, ведь она использует состояние count. Если count изменится, эффект должен быть вызван заново. Можно, конечно, указать в списке зависимостей сам count, но ведь функция foo может использовать еще какие-нибудь данные, можно что-то упустить.
С другой стороны, функция foo (ее идентичность) будет меняться при каждом рендере. Это создаст замкнутый круг:
- изменился count при клике на кнопку
- произошел перерендер
- функция foo создалась заново
- поэтому вызван эффект
- вызов foo изменяет состояние fooCount
- происходит перерендер
- функция foo создалась заново
- поэтому вызван эффект... 🤦♂️ (хотя не должен быть вызван, ведь count-то не изменился)
Варианты решения
👉 объявить foo снаружи компонента (при этом она не сможет ссылаться на пропсы и состояние)
👉 переместить foo внутрь эффекта (тогда она не будет пересоздаваться, и в зависимостях ее указывать не нужно)
👉 убедиться, что foo не использует никаких данных компонента, которые могут измениться при перерендере (и тогда не указывать ее в зависимостях)
👉 создать foo с использованием хука useCallback и указанием зависимостей (тогда ее идентичность не будет меняться между рендерами)
https://codepen.io/furrycat/pen/MWmKKwZ?editors=0011
#ошибки #примерыкода #хуки
Если мы указываем для хука список зависимостей (useEffect, useLayoutEffect, useMemo, useCallback, useImperativeHandle), в него должны войти все использованные значения, которые задействованы в потоке данных React, включая пропсы, состояние и их производные.
А что если одно из этих значений функция - внешняя по отношению к вызову хука? Нужно ли ее указывать в зависимостях к хуку useEffect. (см. прикрепленный скриншот)
С одной стороны - да, ведь она использует состояние count. Если count изменится, эффект должен быть вызван заново. Можно, конечно, указать в списке зависимостей сам count, но ведь функция foo может использовать еще какие-нибудь данные, можно что-то упустить.
С другой стороны, функция foo (ее идентичность) будет меняться при каждом рендере. Это создаст замкнутый круг:
- изменился count при клике на кнопку
- произошел перерендер
- функция foo создалась заново
- поэтому вызван эффект
- вызов foo изменяет состояние fooCount
- происходит перерендер
- функция foo создалась заново
- поэтому вызван эффект... 🤦♂️ (хотя не должен быть вызван, ведь count-то не изменился)
Варианты решения
👉 объявить foo снаружи компонента (при этом она не сможет ссылаться на пропсы и состояние)
👉 переместить foo внутрь эффекта (тогда она не будет пересоздаваться, и в зависимостях ее указывать не нужно)
👉 убедиться, что foo не использует никаких данных компонента, которые могут измениться при перерендере (и тогда не указывать ее в зависимостях)
👉 создать foo с использованием хука useCallback и указанием зависимостей (тогда ее идентичность не будет меняться между рендерами)
https://codepen.io/furrycat/pen/MWmKKwZ?editors=0011
#ошибки #примерыкода #хуки
Инициализация состояния
Хук useState может принимать функцию вместо дефолтного значения. Гарантируется, что эта функция будет вызвана всего один раз при первом рендере. Таким образом можно инициализировать сложные состояния - затратные операции будут выполнены лишь один раз.
#хуки #документация #важно
Хук useState может принимать функцию вместо дефолтного значения. Гарантируется, что эта функция будет вызвана всего один раз при первом рендере. Таким образом можно инициализировать сложные состояния - затратные операции будут выполнены лишь один раз.
#хуки #документация #важно
👍1