Начало работы с API React Hooks

Опубликовано: 2022-03-10
Краткое резюме ↬ В этом руководстве вы узнаете и поймете, что такое хуки React, основные доступные хуки React, а также примеры того, как их писать для ваших приложений React. В процессе вы также узнаете о некоторых дополнительных хуках, поставляемых с React 16.8, а также о том, как писать свои собственные хуки React.

Когда React 16.8 был официально выпущен в начале февраля 2019 года, он поставлялся с дополнительным API, который позволяет вам использовать состояние и другие функции в React без написания класса. Этот дополнительный API называется Hooks , и они становятся популярными в экосистеме React, от проектов с открытым исходным кодом до использования в производственных приложениях.

React Hooks полностью опциональны, что означает, что переписывание существующего кода не требуется, они не содержат критических изменений и доступны для использования с выпуском React 16.8. Некоторые любопытные разработчики использовали Hooks API еще до того, как он был официально выпущен, но тогда он не был стабильным и был лишь экспериментальной функцией. Теперь он стабилен и рекомендуется для использования разработчиками React.

Примечание : мы не будем говорить о React или JavaScript в целом. Хорошее знание ReactJS и JavaScript пригодится вам при работе с этим руководством.

Что такое React-хуки?

React Hooks — это встроенные функции, которые позволяют разработчикам React использовать методы состояния и жизненного цикла внутри функциональных компонентов. Они также работают вместе с существующим кодом, поэтому их можно легко внедрить в кодовую базу. То, как хуки были представлены публике, заключалось в том, что они позволяют разработчикам использовать состояние в функциональных компонентах, но внутри хуки гораздо мощнее. Они позволяют разработчикам React пользоваться следующими преимуществами:

  • Улучшено повторное использование кода;
  • Улучшенная композиция кода;
  • Улучшенные значения по умолчанию;
  • Совместное использование невизуальной логики с использованием пользовательских хуков;
  • Гибкость перемещения вверх и вниз по дереву components .

С React Hooks разработчики получают возможность использовать функциональные компоненты практически для всего, что им нужно, от простого рендеринга пользовательского интерфейса до обработки состояния и логики — что довольно удобно.

Мотивация, стоящая за выпуском React Hooks

Согласно официальной документации ReactJS, выпуск React Hooks вызван следующими причинами:

  • Повторное использование логики с отслеживанием состояния между компонентами затруднено.
    С помощью хуков вы можете повторно использовать логику между своими компонентами, не изменяя их архитектуру или структуру.
  • Сложные компоненты могут быть трудными для понимания.
    Когда компоненты становятся больше и выполняют множество операций, в долгосрочной перспективе их становится трудно понять. Хуки решают эту проблему, позволяя вам разделить конкретный компонент на различные более мелкие функции в зависимости от того, какие части этого отдельного компонента связаны (например, настройка подписки или выборка данных), вместо того, чтобы принудительно разделять на основе методов жизненного цикла.
  • Классы довольно запутанные.
    Классы мешают правильному изучению React; вам нужно будет понять, как this работает в JavaScript, что отличается от других языков. React Hooks решает эту проблему, позволяя разработчикам использовать лучшие функции React без использования классов.
Еще после прыжка! Продолжить чтение ниже ↓

Правила крючков

Есть два основных правила, которых необходимо строго придерживаться, как указано основной командой React, которые они изложили в документации предложения хуков.

  • Не используйте хуки внутри циклов, условий или вложенных функций;
  • Используйте хуки только внутри React Functions.

Основные хуки React

Есть 10 встроенных хуков, которые поставляются с React 16.8, но основные (обычно используемые) хуки включают в себя:

  • useState()
  • useEffect()
  • useContext()
  • useReducer()

Это 4 основных хука, которые обычно используются разработчиками React, внедрившими React Hooks в свои кодовые базы.

useState()

useState() позволяет разработчикам React обновлять, обрабатывать и манипулировать состоянием внутри функциональных компонентов без необходимости преобразовывать его в компонент класса. Давайте используем приведенный ниже фрагмент кода — простой компонент счетчика возраста, и мы будем использовать его для объяснения возможностей и синтаксиса useState() .

 function App() { const [age, setAge] = useState(19); const handleClick = () => setAge(age + 1) return <div> I am {age} Years Old <div> <button onClick={handleClick}>Increase my age! </button> </div> </div> }

Если вы заметили, наш компонент выглядит довольно просто, лаконично, и теперь он является функциональным компонентом, а также не имеет того уровня сложности, который был бы у компонента класса.

useState() получает начальное состояние в качестве аргумента, а затем возвращает, используя деструктурирование массива в JavaScript, две переменные в массиве могут быть названы what. Первая переменная — это фактическое состояние, а вторая переменная — это функция, предназначенная для обновления состояния путем предоставления нового состояния.

Наше готовое приложение React (большой предварительный просмотр)

Вот как должен выглядеть наш компонент при рендеринге в нашем приложении React. Нажав на кнопку «Увеличить мой возраст», состояние возраста изменится, и компонент будет работать так же, как компонент класса с состоянием.

useEffect()

useEffect() принимает функцию, которая будет содержать эффективный код. В функциональных компонентах такие эффекты, как мутации, подписки, таймеры, ведение журнала и другие эффекты, не могут быть размещены внутри функционального компонента, потому что это может привести к множеству несоответствий при отображении пользовательского интерфейса, а также к запутанным ошибкам.

При использовании useEffect() переданная в него эффективная функция будет выполняться сразу после отображения рендера на экране. Эффекты в основном заглядывают в императивный способ создания пользовательских интерфейсов, который сильно отличается от функционального способа React.

По умолчанию эффекты выполняются в основном после завершения рендеринга, но вы также можете активировать их при изменении определенных значений.

useEffect() в основном используется для побочных эффектов, которые обычно используются для взаимодействия с Browser/DOM ​​API или внешней API-подобной выборкой данных или подписками. Кроме того, если вы уже знакомы с тем, как работают методы жизненного цикла React, вы также можете рассматривать useEffect() как монтирование , обновление и размонтирование компонентов — все это объединено в одной функции. Это позволяет нам воспроизводить методы жизненного цикла в функциональных компонентах.

Мы будем использовать фрагменты кода ниже, чтобы объяснить самый простой способ, который мы можем использовать, используя useEffect() .

Шаг 1: Определите состояние вашего приложения

 import React, {useState} from 'react'; function App() { //Define State const [name, setName] = useState({firstName: 'name', surname: 'surname'}); const [title, setTitle] = useState('BIO'); return( <div> <h1>Title: {title}</h1> <h3>Name: {name.firstName}</h3> <h3>Surname: {name.surname}</h3> </div> ); }; export default App

Точно так же, как мы обсуждали в предыдущем разделе, как использовать useState() для обработки состояния внутри функциональных компонентов, мы использовали его в нашем фрагменте кода, чтобы установить состояние для нашего приложения, которое отображает мое полное имя.

Шаг 2: вызов хука useEffect

 import React, {useState, useEffect} from 'react'; function App() { //Define State const [name, setName] = useState({firstName: 'name', surname: 'surname'}); const [title, setTitle] = useState('BIO'); //Call the use effect hook useEffect(() => { setName({FirstName: 'Shedrack', surname: 'Akintayo'}) }, [])//pass in an empty array as a second argument return( <div> <h1>Title: {title}</h1> <h3>Name: {name.firstName}</h3> <h3>Surname: {name.surname}</h3> </div> ); }; export default App

Теперь мы импортировали хук useEffect , а также использовали useEffect() для установки состояния нашего свойства имени и фамилии, что довольно аккуратно и лаконично.

Вы могли заметить хук useEffect во втором аргументе, который представляет собой пустой массив; это потому, что он содержит вызов setFullName , у которого нет списка зависимостей. Передача второго аргумента предотвратит бесконечную цепочку обновлений ( componentDidUpdate() ), а также позволит нашему useEffect() действовать как метод жизненного цикла componentDidMount и выполнять рендеринг один раз без повторного рендеринга при каждом изменении в дереве.

Наше приложение React теперь должно выглядеть так:

Приложение React с использованием useEffect (большой предварительный просмотр)

Мы также можем использовать изменение свойства title нашего приложения внутри функции useEffect() , вызвав функцию setTitle() , например так:

 import React, {useState, useEffect} from 'react'; function App() { //Define State const [name, setName] = useState({firstName: 'name', surname: 'surname'}); const [title, setTitle] = useState('BIO'); //Call the use effect hook useEffect(() => { setName({firstName: 'Shedrack', surname: 'Akintayo'}) setTitle({'My Full Name'}) //Set Title }, [])// pass in an empty array as a second argument return( <div> <h1>Title: {title}</h1> <h3>Name: {name.firstName}</h3> <h3>Surname: {name.surname}</h3> </div> ); }; export default App

Теперь, после повторного рендеринга нашего приложения, оно показывает новый заголовок.

Наш готовый проект (большой превью)

useContext()

useContext() принимает объект контекста, то есть значение, которое возвращается из React.createContext , а затем возвращает текущее значение контекста для этого контекста.

Этот хук дает функциональным компонентам легкий доступ к контексту вашего приложения React. До того, как был введен хук useContext , вам нужно было настроить contextType или <Consumer> для доступа к вашему глобальному состоянию, переданному от какого-либо провайдера в компоненте класса.

По сути, хук useContext работает с React Context API, который позволяет глубоко обмениваться данными в вашем приложении без необходимости вручную передавать реквизиты вашего приложения на различные уровни. Теперь useContext() делает использование Context немного проще.

Приведенные ниже фрагменты кода показывают, как работает Context API и как useContext делает его лучше.

Обычный способ использования контекстного API

 import React from "react"; import ReactDOM from "react-dom"; const NumberContext = React.createContext(); function App() { return ( <NumberContext.Provider value={45}> <div> <Display /> </div> </NumberContext.Provider> ); } function Display() { return ( <NumberContext.Consumer> {value => <div>The answer to the question is {value}.</div>} </NumberContext.Consumer> ); } ReactDOM.render(<App />, document.querySelector("#root"));

Давайте теперь разберем фрагмент кода и объясним каждую концепцию.

Ниже мы создаем контекст с именем NumberContext . Он предназначен для возврата объекта с двумя значениями: { Provider, Consumer } .

 const NumberContext = React.createContext();

Затем мы используем значение Provider , которое было возвращено из созданного нами NumberContext , чтобы сделать конкретное значение доступным для всех дочерних элементов.

 function App() { return ( <NumberContext.Provider value={45}> <div> <Display /> </div> </NumberContext.Provider> ); }

При этом мы можем использовать значение Consumer , которое было возвращено из созданного нами NumberContext , чтобы получить значение, которое мы сделали доступным для всех дочерних элементов. Если вы заметили, этот компонент не получил никакого реквизита.

 function Display() { return ( <NumberContext.Consumer> {value => <div>The answer to the question is {value}.</div>} </NumberContext.Consumer> ); } ReactDOM.render(<App />, document.querySelector("#root"));

Обратите внимание, как мы смогли получить значение из компонента App в компонент Display , обернув наше содержимое в NumberContext.Consumer и используя метод render props для извлечения значения и его рендеринга.

Все работает хорошо, и метод render props, который мы использовали, является действительно хорошим шаблоном для обработки динамических данных, но в долгосрочной перспективе он вносит некоторую ненужную вложенность и путаницу, если вы к этому не привыкли.

Использование метода useContext

Чтобы объяснить метод useContext , мы перепишем компонент Display , используя хук useContext.

 // import useContext (or we could write React.useContext) import React, { useContext } from 'react'; // old code goes here function Display() { const value = useContext(NumberContext); return <div>The answer is {value}.</div>; }

Это все, что нам нужно сделать, чтобы отобразить нашу ценность. Довольно аккуратно, правда? Вы вызываете useContext() и передаете объект контекста, который мы создали, и мы извлекаем из него значение.

Примечание. Не забывайте, что аргумент, передаваемый хуку useContext, должен быть самим объектом контекста, и любой компонент, вызывающий useContext, всегда будет перерисовываться при изменении значения контекста.

useReducer()

useReducer используется для обработки сложных состояний и переходов в состоянии. Он принимает функцию reducer , а также ввод начального состояния; затем он возвращает текущее состояние, а также функцию dispatch в качестве вывода посредством деструктуризации массива.

Приведенный ниже код является правильным синтаксисом для использования хука useReducer .

 const [state, dispatch] = useReducer(reducer, initialArg, init);

Это своего рода альтернатива useState ; обычно предпочтительнее использовать состояние, когда у вас есть сложная логика состояния, связанная с несколькими useState , или когда следующее состояние зависит от предыдущего.

Доступны другие хуки React

useCallback Этот хук возвращает функцию обратного вызова, которая запоминается и изменяется только в случае изменения одной зависимости в дереве зависимостей.
useMemo Этот хук возвращает запомненное значение, вы можете передать функцию «создать», а также массив зависимостей. Возвращаемое им значение будет снова использовать запомненное значение только в том случае, если одна из зависимостей в дереве зависимостей изменится.
useRef Этот хук возвращает изменяемый объект ref, чье свойство .current инициализируется переданным аргументом ( initialValue ). Возвращенный объект будет доступен в течение всего срока службы компонента.
useImperativeHandle Этот хук используется для настройки значения экземпляра, которое становится доступным для родительских компонентов при использовании ссылок в React.
useLayoutEffect Этот хук похож на хук useEffect , однако срабатывает синхронно после всех мутаций DOM. Он также отображается так же, как componentDidUpdate и componentDidMount .
useDebugValue Этот хук можно использовать для отображения метки для пользовательских хуков в React Dev Tools. Это очень полезно для отладки с помощью React Dev Tools.

Пользовательские хуки React

«Пользовательский хук» — это функция JavaScript, имена которой начинаются со слова use и могут использоваться для вызова других хуков. Он также позволяет извлекать логику компонента в повторно используемые функции; это обычные функции JavaScript, которые могут использовать внутри себя другие хуки, а также содержат общую логику с отслеживанием состояния, которую можно использовать в нескольких компонентах.

Фрагменты кода ниже демонстрируют пример пользовательского React Hook для реализации бесконечной прокрутки (автор Paulo Levy):

 import { useState } from "react"; export const useInfiniteScroll = (start = 30, pace = 10) => { const [limit, setLimit] = useState(start); window.onscroll = () => { if ( window.innerHeight + document.documentElement.scrollTop === document.documentElement.offsetHeight ) { setLimit(limit + pace); } }; return limit; };

Этот пользовательский хук принимает два аргумента: start и pace . Аргумент start — это начальное количество элементов, которые должны быть отображены, а аргумент темпа — это последующее количество элементов, которые должны быть отображены. По умолчанию аргументы start и pace установлены на 30 и 10 соответственно, что означает, что вы действительно можете вызвать хук без каких-либо аргументов, и вместо них будут использоваться эти значения по умолчанию.

Таким образом, чтобы использовать этот хук в приложении React, мы будем использовать его с онлайн-API, который возвращает «поддельные» данные:

 import React, { useState, useEffect } from "react"; import { useInfiniteScroll } from "./useInfiniteScroll"; const App = () => { let infiniteScroll = useInfiniteScroll(); const [tableContent, setTableContent] = useState([]); useEffect(() => { fetch("https://jsonplaceholder.typicode.com/todos/") .then(response => response.json()) .then(json => setTableContent(json)); }, []); return ( <div style={{ textAlign: "center" }}> <table> <thead> <tr> <th>User ID</th> <th>Title</th> </tr> </thead> <tbody> {tableContent.slice(0, infiniteScroll).map(content => { return ( <tr key={content.id}> <td style={{ paddingTop: "10px" }}>{content.userId}</td> <td style={{ paddingTop: "10px" }}>{content.title}</td> </tr> ); })} </tbody> </table> </div> ); }; export default App;

Приведенный выше код отобразит список поддельных данных ( userID и title ), которые используют хук бесконечной прокрутки для отображения начального количества данных на экране.

Заключение

Надеюсь, вам понравилось работать с этим уроком. Вы всегда можете прочитать больше о React Hooks из приведенных ниже ссылок.

Если у вас есть какие-либо вопросы, вы можете оставить их в разделе комментариев, и я буду рад ответить на каждый из них!

Вспомогательный репозиторий для этой статьи доступен на Github.

Ресурсы и дополнительная литература

  • «Справочник по API хуков», React.js Docs
  • «Что такое React Hooks?», Робин Вирух.
  • «Как работает хук useContext », Дэйв Седдиа.
  • «React Hooks: как использовать useEffect() », Хоссейн Ахмади, Medium
  • «Написание собственных пользовательских хуков React», Аюш Джайсвал, Medium
  • «Простые для понимания рецепты хуков React», Гейб Рэгланд, useHooks()