React API
Часть методов, предоставляемых библиотекой, мы уже разобрали. Оставшиеся в основном относятся к работе с DOM-элементами. В большинстве случаев с этим успешно справляется синтаксис JSX, но на всякий случай, вот список:
👉 React.createElement() - создает новый React-элемент
👉 React.createFactory() - создает фабрику React-элементов определенного типа
👉 React.cloneElement() () - клонирует React-элемент и возвращает копию
👉 React.isValidElement() - проверяет, является ли объект элементом React
👉 React.Children() - набор функций для работы со структурой this.props.children
ReactDOM API
Пакет react-dom предоставляет специфические для DOM методы, которые могут быть использованы на верхнем уровне вашего приложения. Мы уже знакомы с двумя:
👉 ReactDOM.render() - рендерит React-элемент в DOM-элемент
👉 ReactDOM.createPortal() - создает портал для рендера компонента вне родительского DOM-элемента
А вот остальные:
👉 ReactDOM.hydrate() - нужен для гидратации контейнера при серверном рендеринге. В этом мы будем разбираться позже
👉 ReactDOM.unmountComponentAtNode() - Удаляет смонтированный компонент React из DOM
ReactDOMServer
Объект с набором методов для генерирования статической разметки. Используется на Node-сервере, вернемся к нему позже.
Страница в документации (рус.): https://ru.reactjs.org/docs/react-dom-server.html
#api #документация
Часть методов, предоставляемых библиотекой, мы уже разобрали. Оставшиеся в основном относятся к работе с DOM-элементами. В большинстве случаев с этим успешно справляется синтаксис JSX, но на всякий случай, вот список:
👉 React.createElement() - создает новый React-элемент
👉 React.createFactory() - создает фабрику React-элементов определенного типа
👉 React.cloneElement() () - клонирует React-элемент и возвращает копию
👉 React.isValidElement() - проверяет, является ли объект элементом React
👉 React.Children() - набор функций для работы со структурой this.props.children
ReactDOM API
Пакет react-dom предоставляет специфические для DOM методы, которые могут быть использованы на верхнем уровне вашего приложения. Мы уже знакомы с двумя:
👉 ReactDOM.render() - рендерит React-элемент в DOM-элемент
👉 ReactDOM.createPortal() - создает портал для рендера компонента вне родительского DOM-элемента
А вот остальные:
👉 ReactDOM.hydrate() - нужен для гидратации контейнера при серверном рендеринге. В этом мы будем разбираться позже
👉 ReactDOM.unmountComponentAtNode() - Удаляет смонтированный компонент React из DOM
ReactDOMServer
Объект с набором методов для генерирования статической разметки. Используется на Node-сервере, вернемся к нему позже.
Страница в документации (рус.): https://ru.reactjs.org/docs/react-dom-server.html
#api #документация
ru.legacy.reactjs.org
React API верхнего уровня – React
JavaScript-библиотека для создания пользовательских интерфейсов
Различия между React и HTML
React - это JavaScript, поэтому в некоторых аспектах его синтаксис отличается от стандартного HTML. Все свойства и атрибуты DOM-элементов должны указываться в camelCase (tabIndex вместо tabindex). aria-* и data-* атрибуты остаются как есть.
* className вместо class
* dangerouslySetInnerHTML вместо innerHTML
* htmlFor вместо for
* onChange вместо onInput - для обработки ввода в реальном времени
* value для input/textarea/select
* value на теге select вместо атрибутов selected на тегах option
* style в виде объекта
#документация #важно #jsx
React - это JavaScript, поэтому в некоторых аспектах его синтаксис отличается от стандартного HTML. Все свойства и атрибуты DOM-элементов должны указываться в camelCase (tabIndex вместо tabindex). aria-* и data-* атрибуты остаются как есть.
* className вместо class
* dangerouslySetInnerHTML вместо innerHTML
* htmlFor вместо for
* onChange вместо onInput - для обработки ввода в реальном времени
* value для input/textarea/select
* value на теге select вместо атрибутов selected на тегах option
* style в виде объекта
#документация #важно #jsx
Synthetic Event
React оборачивает нативные события DOM в обертку Synthetic Event. Это нужно, чтобы во всех браузерах все работало одинаково. Интерфейс Synthetic Event соотвествует интерфейсу обычного Event, так что никаких проблем тут не возникает. Есть некоторые тонкости, например, синтетическое событие onMouseLeave - это на самом деле mouseout под капотом.
Нативное событие доступно в свойстве nativeEvent.
Полный список поддерживаемых событий в документации (рус.): https://ru.reactjs.org/docs/events.html#supported-events
Обработчики для них вызываются на фазе всплытия (bubbling). Чтобы ловить события на фазе перехвата (capture), к имени обработчика нужно прибавить Capture - onClickCapture вместо onClick.
#обработкасобытий #документация
React оборачивает нативные события DOM в обертку Synthetic Event. Это нужно, чтобы во всех браузерах все работало одинаково. Интерфейс Synthetic Event соотвествует интерфейсу обычного Event, так что никаких проблем тут не возникает. Есть некоторые тонкости, например, синтетическое событие onMouseLeave - это на самом деле mouseout под капотом.
Нативное событие доступно в свойстве nativeEvent.
Полный список поддерживаемых событий в документации (рус.): https://ru.reactjs.org/docs/events.html#supported-events
Обработчики для них вызываются на фазе всплытия (bubbling). Чтобы ловить события на фазе перехвата (capture), к имени обработчика нужно прибавить Capture - onClickCapture вместо onClick.
#обработкасобытий #документация
ru.legacy.reactjs.org
SyntheticEvent – React
JavaScript-библиотека для создания пользовательских интерфейсов
Введение в хуки
Переходим к очень интересной теме - хукам.
Они появились в React не так давно и полностью совместимы с предыдущими версиями библиотеки.
Мы уже поняли, что классовые компоненты обладают большими преимуществами перед функциональными в плане гибкости. У классов есть состояние и методы жизненного цикла, а у функций нет.
Хуки являются в некотором смысле альтернативой классовым компонентам, они позволяют использовать возможности классов в функциях. Как именно - будем разбираться дальше.
Основная идея хуков - извлечь и инкапсулировать логику изменения состояния, чтобы ее можно было отдельно тестировать и переиспользовать. То есть, хук - это, по идее, некоторая логика, которая существует сама по себе и может быть присоединена к любому компоненту посредством композиции.
С внедрением хуков React становится более "функциональным".
#документация #началоработы #хуки
Переходим к очень интересной теме - хукам.
Они появились в React не так давно и полностью совместимы с предыдущими версиями библиотеки.
Мы уже поняли, что классовые компоненты обладают большими преимуществами перед функциональными в плане гибкости. У классов есть состояние и методы жизненного цикла, а у функций нет.
Хуки являются в некотором смысле альтернативой классовым компонентам, они позволяют использовать возможности классов в функциях. Как именно - будем разбираться дальше.
Основная идея хуков - извлечь и инкапсулировать логику изменения состояния, чтобы ее можно было отдельно тестировать и переиспользовать. То есть, хук - это, по идее, некоторая логика, которая существует сама по себе и может быть присоединена к любому компоненту посредством композиции.
С внедрением хуков React становится более "функциональным".
#документация #началоработы #хуки
Правила хуков
Прежде чем начать использовать хуки, ознакомимся с правилами их использования.
👉 Хуки следует вызывать только на верхнем уровне. Не вызывайте хуки внутри циклов, условий или вложенных функций.
Исполнение этого правила гарантирует, что хуки вызываются в одинаковой последовательности при каждом рендере компонента. Так 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, основанный на модели событий.
#документация #хуки #примерыкода