Лучшие практики с React Hooks

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

React Hooks — это новое дополнение в React 16.8, которое позволяет вам использовать состояние и другие функции React без написания компонента class . Другими словами, хуки — это функции, которые позволяют вам «подключаться» к функциям состояния и жизненного цикла React из функциональных компонентов. (Они не работают внутри компонентов class .)

React предоставляет несколько встроенных хуков, таких как useState . Вы также можете создавать свои собственные хуки для повторного использования поведения с отслеживанием состояния между различными компонентами. В приведенном ниже примере показан счетчик, состояние которого управляется с помощью useState() . Каждый раз, когда вы нажимаете на кнопку, мы используем setCount() для обновления значения count на 1 .

См. Pen [пример React Hook с Counter] (https://codepen.io/smashingmag/pen/QWbXMyM) от Adeneye Abiodun David.

См. пример Pen React Hook с Counter от Adeneye Abiodun David.

В этом примере отображается счетчик со значением 0 . Когда вы нажимаете кнопку, значение увеличивается на 1 . Начальное значение компонента определяется с помощью useState .

 const [count, setCount] = useState(0)

Как видите, мы установили его равным 0 . Затем мы используем метод onClick onClick() для вызова setCount , когда мы хотим увеличить значение.

 <button onClick={() => setCount(count + 1)}> Click me </button>

До выпуска React Hooks в этом примере использовалось бы больше строк кода, так как нам пришлось бы использовать компонент class .

Еще после прыжка! Продолжить чтение ниже ↓

Правила использования хуков React

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

React Hooks — это функции JavaScript, но при их использовании необходимо соблюдать два правила.

  1. Call Hooks на верхнем уровне;
  2. Вызывайте хуки только из компонентов React.

Примечание . Эти два правила были введены в React Hooks, а не являются частью самого JavaScript.

Рассмотрим эти правила более подробно.

Call Hooks на верхнем уровне

Не вызывайте хуки внутри циклов, условий или вложенных функций. Всегда используйте хуки на верхнем уровне вашей функции React. Следуя этому правилу, вы гарантируете, что хуки вызываются в одном и том же порядке каждый раз при рендеринге компонента. Именно это позволяет React правильно сохранять состояние хуков между несколькими useState и useEffect .

Давайте создадим компонент Form , который будет иметь два состояния:

  • accountName
  • accountDetail

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

Теперь этот компонент, возможно, будет успешно управлять своим состоянием, если оно останется неизменным между несколькими вызовами useState и useEffect .

 function Form() { // 1. Use the accountName state variable const [accountName, setAccountName] = useState('David'); // 2. Use an effect for persisting the form useEffect(function persistForm() { localStorage.setItem('formData', accountName); }); // 3. Use the accountDetail state variable const [accountDetail, setAccountDetail] = useState('Active'); // 4. Use an effect for updating the title useEffect(function updateStatus() { document.title = accountName + ' ' + accountDetail; }); // ... }

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

 // ------------ useState('David') // 1. Initialize the accountName state variable with 'David' useEffect(persistForm) // 2. Add an effect for persisting the form useState('Active') // 3. Initialize the accountdetail state variable with 'Active' useEffect(updateStatus) // 4. Add an effect for updating the status // ------------- // Second render // ------------- useState('David') // 1. Read the accountName state variable (argument is ignored) useEffect(persistForm) // 2. Replace the effect for persisting the form useState('Active') // 3. Read the accountDetail state variable (argument is ignored) useEffect(updateStatus) // 4. Replace the effect for updating the status // ...

Это порядок, в котором React вызывает наши хуки. Поскольку порядок остается прежним, он сможет сохранить состояние нашего компонента. Но что произойдет, если мы поместим вызов Hook внутри условия?

 // We're breaking the first rule by using a Hook in a condition if (accountName !== '') { useEffect(function persistForm() { localStorage.setItem('formData', accountName); }); }

Условие true accountName !== '' выполняется при первом рендеринге, поэтому мы запускаем этот хук. Однако при следующем рендеринге пользователь может очистить форму, что сделает условие false . Теперь, когда мы пропускаем этот хук во время рендеринга, порядок вызовов хука становится другим:

 useState('David') // 1. Read the accountName state variable (argument is ignored) // useEffect(persistForm) // This Hook was skipped! useState('Active') // 2 (but was 3). Fail to read the accountDetails state variable useEffect(updateStatus) // 3 (but was 4). Fail to replace the effect

React не будет знать, что вернуть для второго вызова useState Hook. React ожидал, что второй вызов хука в этом компоненте соответствует эффекту persistForm , как и во время предыдущего рендера, но это не так. С этого момента каждый следующий вызов Hook после того, который мы пропустили, также смещался на единицу, что приводило к ошибкам.

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

Примечание . Ознакомьтесь с документацией React Hook, чтобы узнать больше по этой теме.

Вызов хуков только из компонентов React

Не вызывайте хуки из обычных функций JavaScript. Вместо этого вы можете вызывать хуки из функциональных компонентов React. Давайте посмотрим на разницу между функцией JavaScript и компонентом React ниже:

Функция JavaScript

 import { useState } = "react"; function toCelsius(fahrenheit) { const [name, setName] = useState("David"); return (5/9) * (fahrenheit-32); } document.getElementById("demo").innerHTML = toCelsius;

Здесь мы импортируем хук useState из пакета React, а затем объявляем нашу функцию. Но это неверно, так как это не компонент React.

Реагировать на функцию

 import React, { useState} from "react"; import ReactDOM from "react-dom"; function Account(props) { const [name, setName] = useState("David"); return <p>Hello, {name}! The price is <b>{props.total}</b> and the total amount is <b>{props.amount}</b></p> } ReactDom.render( <Account total={20} amount={5000} />, document.getElementById('root') );

Несмотря на то, что тело обоих выглядит одинаково, последнее становится компонентом, когда мы импортируем React в файл. Именно это позволяет нам использовать внутри такие вещи, как хуки JSX и React.

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

Вызов хуков из пользовательских хуков

Пользовательский хук — это функция JavaScript, имя которой начинается с use и которая может вызывать другие хуки. Например, useUserName используется под пользовательским хуком, который вызывает useState и useEffect . Он извлекает данные из API, перебирает данные и вызывает setIsPresent() , если конкретное имя пользователя, которое он получил, присутствует в данных API.

 export default function useUserName(userName) { const [isPresent, setIsPresent] = useState(false); useEffect(() => { const data = MockedApi.fetchData(); data.then((res) => { res.forEach((e) => { if (e.name === userName) { setIsPresent(true); } }); }); }); return isPresent; }

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

Следуя этому правилу, вы гарантируете, что вся логика с отслеживанием состояния в компоненте четко видна из его исходного кода.

Плагин ESLint

Плагин ESLint под названием eslint-plugin-react-hooks обеспечивает соблюдение вышеуказанных правил. Это удобно для обеспечения соблюдения правил при работе над проектом. Я предлагаю вам использовать этот плагин при работе над вашим проектом, особенно при работе с другими. Вы можете добавить этот плагин в свой проект, если хотите попробовать:

 // Your ESLint configuration { "plugins": [ // ... "react-hooks" ], "rules": { // ... "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks "react-hooks/exhaustive-deps": "warn" // Checks effect dependencies } }

Этот плагин по умолчанию включен в приложение Create React. Поэтому вам не нужно добавлять его, если вы загружаете свои приложения React с помощью Create-React-App.

Мышление крючками

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

Самый простой способ определить компонент в React — написать функцию JavaScript, которая возвращает элемент React:

 function Welcome(props) { return <h1>Hello, {props.name}</h1>; }

Компонент Welcome принимает props , которые представляют собой объект, содержащий данные и возвращающий элемент React. Затем мы можем импортировать и визуализировать этот компонент в другом компоненте.

Компонент class использует методологию программирования, называемую инкапсуляцией , что в основном означает, что все, что относится к компоненту класса, будет жить внутри него. Методы жизненного цикла ( constructors , componentDidMount() , render и т. д.) придают компонентам предсказуемую структуру.

Инкапсуляция — одна из основ ООП (объектно-ориентированного программирования). Это относится к объединению данных в методы, которые работают с этими данными, и используется для сокрытия значений или состояния объекта структурированных данных внутри класса, предотвращая прямой доступ к ним неавторизованных сторон.

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

Функциональный компонент

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

 function { useHook{...}; useHook{...}; useHook{...}; return (
...
); }

Компонент класса

Компонент class требует расширения от React.Component и создания функции render , которая возвращает элемент React. Это требует больше кода, но также даст вам некоторые преимущества.

 class { constructor(props) {...} componentDidMount() {...} componentWillUnmount() {...} render() {...} }

Есть некоторые преимущества, которые вы получаете, используя функциональные компоненты в React:

  1. Станет проще разделять контейнерные и презентационные компоненты, потому что вам нужно больше думать о состоянии вашего компонента, если у вас нет доступа к setState() в вашем компоненте.
  2. Функциональные компоненты намного легче читать и тестировать, потому что они представляют собой простые функции JavaScript без состояний или перехватчиков жизненного цикла.
  3. В итоге у вас будет меньше кода.
  4. Команда React упомянула, что в будущих версиях React может быть повышена производительность функциональных компонентов.

Это приводит к первой лучшей практике использования React Hooks.

Лучшие практики использования хуков

1. Упростите свои хуки

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

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

Функциональный компонент v1

 function { useHook(...); useHook(...); useHook(...); return( <div>...</div> ); }

Функциональный компонент v2

 function { useCustomHook(...); useHook(...); useHook(...); return( <div>...</div> ); }

v2 — лучшая версия, потому что она делает хук простым, а все остальные useHook соответственно встроенными. Это позволяет нам создавать функциональные возможности, которые можно повторно использовать в различных компонентах, а также дает нам больше возможностей для эффективного контроля и управления нашими компонентами. Вместо версии 1, в которой наши компоненты замусорены хуками, вам следует использовать версию 2, которая упростит отладку и сделает ваш код чище.

2. Организуйте и структурируйте свои крючки

Одним из преимуществ React Hooks является возможность писать меньше кода, который легко читается. В некоторых случаях количество useEffect() и useState() все еще может сбивать с толку. Когда вы держите свой компонент организованным, это поможет сделать его читабельным и сохранить поток ваших компонентов последовательным и предсказуемым. Если ваши пользовательские хуки слишком сложны, вы всегда можете разбить их на второстепенные хуки. Извлеките логику вашего компонента в пользовательские хуки, чтобы сделать ваш код читабельным.

3. Используйте сниппеты React Hooks

React Hooks Snippets — это расширение Visual Studio Code, которое упрощает и ускоряет работу с React Hooks. В настоящее время поддерживаются пять хуков:

  • useState()
  • useEffect()
  • useContext()
  • useCallback()
  • useMemo()

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

Есть два способа добавить фрагменты React Hooks в свой проект:

  1. Команда
    Запустите VS Code Quick open ( Ctrl + P ), вставьте ext install ALDuncanson.react-hooks-snippets и нажмите Enter .
  2. Торговая площадка расширений
    Запустите VS Code Extension Marketplace ( Ctrl + Shift + X ) и найдите «React Hook Snippets». Затем найдите значок «Alduncanson».

Рекомендую первый фрагмент. Узнайте больше о сниппетах здесь или проверьте последние сниппеты Hooks здесь.

4. Учитывайте правила хуков

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

  • Вызывайте свои хуки только на верхнем уровне. Не вызывайте хуки внутри циклов, условий или вложенных функций.
  • Всегда вызывайте хуки из функциональных компонентов React или из пользовательских хуков, не вызывайте хуки из обычных функций JavaScript.

Плагин ESlint под названием eslint-plugin-react-hooks обеспечивает соблюдение этих двух правил, вы можете добавить этот плагин в свой проект, если хотите, как мы объяснили выше в разделе правил хуков.

Лучшие практики не были полностью решены, потому что хуки все еще относительно новы. Таким образом, принятие должно быть предпринято с осторожностью, как при внедрении любой ранней технологии. Имея это в виду, хуки — это путь к будущему React.

Заключение

Надеюсь, вам понравился этот урок. Мы узнали два самых важных правила React Hooks и научились эффективно мыслить с помощью Hooks. Мы рассмотрели функциональные компоненты и некоторые рекомендации по правильному и эффективному написанию хуков. Какими бы краткими ни были правила, важно сделать их путеводным компасом при написании правил. Если вы склонны забывать об этом, вы можете использовать плагин ESLint, чтобы обеспечить его соблюдение.

Я надеюсь, что вы извлечете все уроки, полученные здесь, в своем следующем проекте React. Удачи!

Ресурсы

  • «Представляем хуки», React Docs
  • «Функциональные и классовые компоненты в React», Дэвид Джох, Medium
  • «Миксины считаются вредными», Дэн Абрамов, React Blog
  • «React Hooks: лучшие практики и изменение мышления», Брайан Мануэле, Medium
  • «React Hooks Snippets for VS Code», Энтони Дэвис, Visual Code Marketplace.