Правила хуков
Прежде чем начать использовать хуки, ознакомимся с правилами их использования.
👉 Хуки следует вызывать только на верхнем уровне. Не вызывайте хуки внутри циклов, условий или вложенных функций.
Исполнение этого правила гарантирует, что хуки вызываются в одинаковой последовательности при каждом рендере компонента. Так React может правильно сохранять состояние между множественными вызовами хуков.
👉 Хуки следует вызывать только из функциональных компонентов React. Не вызывайте хуки из обычных JavaScript-функций. (можно вызывать хуки из пользовательских хуков, о них позже)
Команда React даже создала плагин для ESLint eslint-plugin-react-hooks, который позволяет контролировать выполнение этих правил. (Плагин уже включен в Create React App)
Итак, React очень полагается на порядок вызова хуков внутри компонента, поэтому он должен быть максимально четким.
#документация #хуки
Прежде чем начать использовать хуки, ознакомимся с правилами их использования.
👉 Хуки следует вызывать только на верхнем уровне. Не вызывайте хуки внутри циклов, условий или вложенных функций.
Исполнение этого правила гарантирует, что хуки вызываются в одинаковой последовательности при каждом рендере компонента. Так React может правильно сохранять состояние между множественными вызовами хуков.
👉 Хуки следует вызывать только из функциональных компонентов React. Не вызывайте хуки из обычных JavaScript-функций. (можно вызывать хуки из пользовательских хуков, о них позже)
Команда React даже создала плагин для ESLint eslint-plugin-react-hooks, который позволяет контролировать выполнение этих правил. (Плагин уже включен в Create React App)
Итак, React очень полагается на порядок вызова хуков внутри компонента, поэтому он должен быть максимально четким.
#документация #хуки
npm
npm: eslint-plugin-react-hooks
ESLint rules for React Hooks. Latest version: 5.2.0, last published: 6 months ago. Start using eslint-plugin-react-hooks in your project by running `npm i eslint-plugin-react-hooks`. There are 9681 other projects in the npm registry using eslint-plugin-react…
Хук состояния
Встроенный хук useState является аналогом установки this.state в классовом компоненте и использования this.setState.
https://codepen.io/furrycat/pen/wvdwNde?editors=0010
Вызов функции useState возвращает два параметра (в виде массива):
- собственно состояние (count), которое можно использовать для чтения
- функцию для обновления состояния (setCount, аналог this.setState)
Для их извлечения обычно используется синтаксис деструктуризации массива.
React создает некое внутреннее состояние для этого компонента и запоминает его. При изменении состояния, произойдет перерендер компонента.
В классовых компонентах состояние должно было быть объектом, но здесь это совсем необязательно. По сути, каждый useState соответствует отдельному полю в состоянии, внутри компонента таких вызовов может быть несколько.
Важно:
- при первом рендере компонента useState создает новое состояние. Его можно инициализировать дефолтным значением, передав его в хук.
- при повторных рендерах используется уже созданное ранее состояние.
#хуки #состояние #документация #примерыкода
Встроенный хук useState является аналогом установки this.state в классовом компоненте и использования this.setState.
https://codepen.io/furrycat/pen/wvdwNde?editors=0010
Вызов функции useState возвращает два параметра (в виде массива):
- собственно состояние (count), которое можно использовать для чтения
- функцию для обновления состояния (setCount, аналог this.setState)
Для их извлечения обычно используется синтаксис деструктуризации массива.
React создает некое внутреннее состояние для этого компонента и запоминает его. При изменении состояния, произойдет перерендер компонента.
В классовых компонентах состояние должно было быть объектом, но здесь это совсем необязательно. По сути, каждый useState соответствует отдельному полю в состоянии, внутри компонента таких вызовов может быть несколько.
Важно:
- при первом рендере компонента useState создает новое состояние. Его можно инициализировать дефолтным значением, передав его в хук.
- при повторных рендерах используется уже созданное ранее состояние.
#хуки #состояние #документация #примерыкода
Связь хуков с компонентами
Как именно React понимает, для какого компонента создавать внутреннее состояние при вызове хука useState?
Оказывается, React отслеживает, какой компонент рендерится в данный момент.
У каждого компонента есть "ячейки памяти", в которых могут храниться данные. При рендере указатель устанавливается на первую ячейку.
При вызове хука, React читает (или инициализирует при первом рендере) значение текущей активной ячейки, а указатель сдвигается дальше, на вторую.
Поэтому очень важно, чтобы порядок вызова хуков всегда был одинаковым. Для этого и существуют правила.
Таким образом, если в компоненте вызывается несколько useState, каждый из них создает изолированное состояние.
#хуки #подкапотом #документация
Как именно React понимает, для какого компонента создавать внутреннее состояние при вызове хука useState?
Оказывается, React отслеживает, какой компонент рендерится в данный момент.
У каждого компонента есть "ячейки памяти", в которых могут храниться данные. При рендере указатель устанавливается на первую ячейку.
При вызове хука, React читает (или инициализирует при первом рендере) значение текущей активной ячейки, а указатель сдвигается дальше, на вторую.
Поэтому очень важно, чтобы порядок вызова хуков всегда был одинаковым. Для этого и существуют правила.
Таким образом, если в компоненте вызывается несколько useState, каждый из них создает изолированное состояние.
#хуки #подкапотом #документация
Telegram
React Junior
Хук состояния
Встроенный хук useState является аналогом установки this.state в классовом компоненте и использования this.setState.
https://codepen.io/furrycat/pen/wvdwNde?editors=0010
Вызов функции useState возвращает два параметра (в виде массива):
-…
Встроенный хук useState является аналогом установки this.state в классовом компоненте и использования this.setState.
https://codepen.io/furrycat/pen/wvdwNde?editors=0010
Вызов функции useState возвращает два параметра (в виде массива):
-…
Хук эффекта
Переходим к другому встроенному хуку React - useEffect. По первому впечатлению он посложнее, чем useState, поэтому посвятим ему немного больше времени.
https://codepen.io/furrycat/pen/NWjWvmr?editors=0011
useEffect, как следует из названия, предназначен для выполнения некоторого эффекта - имеется в виду побочный эффект, вроде логирования, запросов к апи, каких-либо подписок и другие подобные вещи, которые нельзя выполнять в фазу рендера.
В классовых компонентах мы делали это в методах componentDidMount (для первого рендера) и componentDidUpdate (для последующих обновлений).
Хук useEffect позволяет делать это в одном месте. Он вызывается после КАЖДОГО рендера, включая первый.
useEffect принимает всего один аргумент - функцию. Собственно это и есть "эффект", который будет вызываться после каждого рендера.
Так как функция-эффект создается прямо внутри компонента, она имеет доступ ко всем внутренним переменным, в т.ч. к "состоянию", созданному с помощью хука useState.
#хуки #документация #примерыкода
Переходим к другому встроенному хуку React - useEffect. По первому впечатлению он посложнее, чем useState, поэтому посвятим ему немного больше времени.
https://codepen.io/furrycat/pen/NWjWvmr?editors=0011
useEffect, как следует из названия, предназначен для выполнения некоторого эффекта - имеется в виду побочный эффект, вроде логирования, запросов к апи, каких-либо подписок и другие подобные вещи, которые нельзя выполнять в фазу рендера.
В классовых компонентах мы делали это в методах componentDidMount (для первого рендера) и componentDidUpdate (для последующих обновлений).
Хук useEffect позволяет делать это в одном месте. Он вызывается после КАЖДОГО рендера, включая первый.
useEffect принимает всего один аргумент - функцию. Собственно это и есть "эффект", который будет вызываться после каждого рендера.
Так как функция-эффект создается прямо внутри компонента, она имеет доступ ко всем внутренним переменным, в т.ч. к "состоянию", созданному с помощью хука useState.
#хуки #документация #примерыкода
Telegram
React Junior
Хук состояния
Встроенный хук useState является аналогом установки this.state в классовом компоненте и использования this.setState.
https://codepen.io/furrycat/pen/wvdwNde?editors=0010
Вызов функции useState возвращает два параметра (в виде массива):
-…
Встроенный хук useState является аналогом установки this.state в классовом компоненте и использования this.setState.
https://codepen.io/furrycat/pen/wvdwNde?editors=0010
Вызов функции useState возвращает два параметра (в виде массива):
-…
Сброс эффекта
Некоторые эффекты занимают ресурсы и требуют после себя сброса. Например, различные подписки. Если при первом рендере компонента, вы подписались на какой-то сервис, то при его размонтировании обязательно нужно освободить память и отписаться.
В классовых компонентах для этого предназначался метод componentWillUnmount. В функциональных эту работу выполняет хук useEffect.
https://codepen.io/furrycat/pen/OJmJxyN?editors=0011
Так получается намного логичнее, так как вся логика одного эффекта (подписка и отписка) объединяется в одном месте.
Чтобы выполнить сброс в нужное время, функция-эффект просто должна вернуть функцию-сброс.
#хуки #документация #примерыкода
Некоторые эффекты занимают ресурсы и требуют после себя сброса. Например, различные подписки. Если при первом рендере компонента, вы подписались на какой-то сервис, то при его размонтировании обязательно нужно освободить память и отписаться.
В классовых компонентах для этого предназначался метод componentWillUnmount. В функциональных эту работу выполняет хук useEffect.
https://codepen.io/furrycat/pen/OJmJxyN?editors=0011
Так получается намного логичнее, так как вся логика одного эффекта (подписка и отписка) объединяется в одном месте.
Чтобы выполнить сброс в нужное время, функция-эффект просто должна вернуть функцию-сброс.
#хуки #документация #примерыкода
Новый эффект при каждом рендере
В предыдущем примере видно, что сброс эффекта происходит не только при размонтировании компонента (как делает componentWillUnmount) - а при каждом рендере. При каждом рендере в useEffect передается новая функция-эффект, а предыдущий эффект в очереди сбрасывается.
Это сделано преднамеренно. По сути в очередь ставится уже новый эффект, независимый от прежнего, имеющий доступ к актуальным данным внутри компонента. Получается, что эффект "принадлежит" текущему рендеру.
Например, ваш компонент получает в пропсах некоторый id, например, id пользователя, и подписывается на события этого пользователя с помощью хука useEffect. При следующем рендере id пользователя поменялся. Следовательно нужно сбросить подписку на предыдущий id прежде чем подписаться на новый, иначе могут возникнуть баги. В классовых компонентах мы могли бы сделать это в методе componentDidUpdate, сравнив старый и новый id.
Теоретически такое поведение (сброс и выполнение эффекта при каждом рендере) может вызывать проблемы с производительностью, но React предлагает решение для оптимизации эффектов, рассмотрим его в следующем посте.
#документация #хуки
В предыдущем примере видно, что сброс эффекта происходит не только при размонтировании компонента (как делает componentWillUnmount) - а при каждом рендере. При каждом рендере в useEffect передается новая функция-эффект, а предыдущий эффект в очереди сбрасывается.
Это сделано преднамеренно. По сути в очередь ставится уже новый эффект, независимый от прежнего, имеющий доступ к актуальным данным внутри компонента. Получается, что эффект "принадлежит" текущему рендеру.
Например, ваш компонент получает в пропсах некоторый id, например, id пользователя, и подписывается на события этого пользователя с помощью хука useEffect. При следующем рендере id пользователя поменялся. Следовательно нужно сбросить подписку на предыдущий id прежде чем подписаться на новый, иначе могут возникнуть баги. В классовых компонентах мы могли бы сделать это в методе componentDidUpdate, сравнив старый и новый id.
Теоретически такое поведение (сброс и выполнение эффекта при каждом рендере) может вызывать проблемы с производительностью, но React предлагает решение для оптимизации эффектов, рассмотрим его в следующем посте.
#документация #хуки
Telegram
React Junior
Сброс эффекта
Некоторые эффекты занимают ресурсы и требуют после себя сброса. Например, различные подписки. Если при первом рендере компонента, вы подписались на какой-то сервис, то при его размонтировании обязательно нужно освободить память и отписаться.…
Некоторые эффекты занимают ресурсы и требуют после себя сброса. Например, различные подписки. Если при первом рендере компонента, вы подписались на какой-то сервис, то при его размонтировании обязательно нужно освободить память и отписаться.…
Пропуск эффектов
В прошлом посте мы разобрали, зачем сброс эффекта useEffect производится при каждом рендере компонента, а не только при его размонтировании. И упомянули метод componentDidUpdate, в котором можно было бы выполнить сброс только если изменился id пользователя в пропсах.
https://codepen.io/furrycat/pen/WNjbrOe?editors=0011
На самом деле, хук useEffect тоже дает такую возможность. В него можно передать второй компонент - массив полей, с которыми связан эффект. Если одно из этих полей изменится, эффект будет вызван. Иначе React его проигнорирует.
Возвращаясь к примеру, если проп id не изменится, то эффект, связанный с ним, не будет вызван (соответственно, предыдущий эффект не будет сброшен).
#документация #хуки #примерыкода
В прошлом посте мы разобрали, зачем сброс эффекта useEffect производится при каждом рендере компонента, а не только при его размонтировании. И упомянули метод componentDidUpdate, в котором можно было бы выполнить сброс только если изменился id пользователя в пропсах.
https://codepen.io/furrycat/pen/WNjbrOe?editors=0011
На самом деле, хук useEffect тоже дает такую возможность. В него можно передать второй компонент - массив полей, с которыми связан эффект. Если одно из этих полей изменится, эффект будет вызван. Иначе React его проигнорирует.
Возвращаясь к примеру, если проп id не изменится, то эффект, связанный с ним, не будет вызван (соответственно, предыдущий эффект не будет сброшен).
#документация #хуки #примерыкода
Плюсы 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)
Пример кода - в прикрепленном скриншоте
#документация #хуки #рефы