Реагировать на хуки

React - потрясающая библиотека. Он становится все более производительным, а опыт разработки - потрясающим с каждым новым выпуском. Сегодня мы поговорим о React Hooks, функции, которая доступна в React v16.7.0-alpha,, потрясающая и мощная, о которой должен знать каждый.

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

Почему крючки?

Упрощает сложные компоненты

Мы часто начинаем с простых компонентов, но со временем они усложняются и превращаются в неуправляемый беспорядок логики с отслеживанием состояния и побочных эффектов. Многие из наших методов жизненного цикла часто содержат смесь несвязанной логики. Например, мы обычно подключаем наш вызов получения данных к методу жизненного циклаcomponentDidMount, но тот же метод componentDidMount также будет использоваться для настройки прослушивателей событий. Отмена регистрации приемника событий выполняется в componentWillUnmount. Таким образом, взаимно связанный код разделяется на части, но в конечном итоге совершенно несвязанный код объединяется в один метод. Это слишком упрощает внесение ошибок и несоответствий. Во многих случаях становится сложно сломать компонент как нашу логику с отслеживанием состояния.

Функциональные компоненты с отслеживанием состояния

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

Предотвращение путаницы в свойствах класса

Некоторые из концепций класса могут сбивать с толку людей, использующих javascript:

  • Понимание того, как «this» работает в JavaScript, который сильно отличается от того, как он работает в большинстве языков.
  • Вы должны не забыть привязать обработчики событий, что очень многословно.
  • Выбор того, когда использовать функциональный компонент или классы, может сбить с толку даже некоторых опытных разработчиков.

Для решения этих проблем React разработал ловушки. Чтобы мы могли использовать больше возможностей React без использования классов.

Что такое крючки?

Hook позволяет использовать состояние, контекст, ссылку и многие другие функции класса без расширения класса. Разве это не круто !!

В этой статье мы рассмотрим 2 хука useState и UseEffect.

useState (State Hook):

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

До хуков, если нам нужно было состояние в функциональном компоненте, мы бы преобразовали его в класс. Итак, для простого кода, как показано ниже, который просто должен отслеживать переменную count и обновлять ее, нам нужен класс до сих пор, но не больше: D.

Вот так выглядит наш код без хуков

import { useState, PureComponent } from 'react';

class Example extends PureComponent {
      constructor(){
          super();
          this.state={
          count=0
        }
     }
render(){
 const { count }=this.state;
 return (
     <div>
       <p>You clicked {count} times</p>
       <button onClick={this.updateCount}>
         Click me
       </button>
     </div>
    );
  }
}

Теперь давайте используем хуки и посмотрим, как они сокращают наши строки кода, а также избавляются от класса: D

import { useState } from 'react';

function Example() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

Итак, в приведенном выше коде мы использовали «useState». Давайте пойдем по очереди, чтобы понять, что происходит.

const [count, setCount] = useState(0);
В строке выше count - это имя переменной, а setCount - имя функции, которая будет использоваться для обновления значения count. useState принимает начальное значение переменной в качестве параметра. В нашем случае мы предоставили 0 в качестве начального значения. Вы также можете передать Object в качестве начального значения.

Вы могли заметить квадратные скобки, когда мы объявляем переменную состояния. Это синтаксис javascript, который называется деструктуризацией массива.

var countStateVariable = useState(0) //this returns an array
var countVar= countStateVariable[0]; 
var countUpdateFunc = countStateVariable[1];

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

Использование нескольких переменных состояния

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

import { useState } from 'react';

function userProfile() {
 const [age, setAge] = useState(80);
  const [favoriteSport, setfavoriteSport] = useState('Tennis');
  const [name, setName] = useState({firstName:'Akhil', lastName:'Choudhary});
return (
    <div>
      <p>Name {name.firstName} {name.lastName} </p>
      <p>Age {age}</p>
      <p>Favorite Sport {favoriteSport}</p>
    </div>
  );
}

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

useEffect Hook

В компоненте React обычно выполняется выборка данных, подписки или ручное изменение DOM. Мы называем эти операции «побочными эффектами», потому что они могут повлиять на другие компоненты и не могут быть выполнены во время рендеринга.

useEffect hook, добавляет возможность выполнять эти действия из функционального компонента. Он служит той же цели, что и componentDidMount, componentDidUpdate и componentWillUnmount в классах React, но объединен в единый API.

Давайте рассмотрим пример, чтобы лучше понять это.

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  componentDidMount() {
    document.title = `You clicked ${this.state.count} times`;
  }

  componentDidUpdate() {
    document.title = `You clicked ${this.state.count} times`;
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

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

Для решения этой проблемы на помощь приходит перехватчик useEffect. Теперь давайте увидим тот же код с использованием хука useEffect.

import { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

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

useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

Используя ловушку useEffect в нашем функциональном компоненте, мы сообщаем React, что есть что-то, что наш компонент хотел бы сделать после каждого рендеринга. Мы передаем функцию ловушке useEffect. Эта функция, которую мы передаем, и есть наш эффект. Внутри нашего эффекта мы устанавливаем заголовок документа с помощью document.title API браузера. Когда React визуализирует наш компонент, он запоминает эффект, который мы использовали, а затем запускает наш эффект после обновления DOM. Это будет происходить для каждого рендера, включая начальный рендеринг.

Обычно настраивают подписку в componentDidMount и очищают ее в componentWillUnmount.

componentDidMount = () => {
  //registering the listener 
  this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this.keyboardDidShow);
};
componentWillUnmount() {
  // removing the listener on unMounting
  if (this.keyboardDidShowListener) {
    this.keyboardDidShowListener.remove();
  }
}

Давайте посмотрим на приведенную выше реализацию с помощью хука useEffect.

useEffect(() => {
    const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this.keyboardDidShow);
return function clearSubscription() {
      this.keyboardDidShowListener.remove();
    };
  });

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

Советы по более эффективному использованию useEffects:

  • Используйте несколько эффектов для разделения проблем -
    Мотивация для использования хуков состоит в том, что обычно методы жизненного цикла класса часто содержат вместе несвязанную логику, но связанная логика разбивается на несколько методов. и с помощью крючков мы хотим это преодолеть. Чтобы использовать ловушку более эффективно, разделите несвязанную логику на разные эффекты.
import { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);
//effect1 for setting up document title
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });
//effect2 for setting subscription
  useEffect(() => {
    const keyboardDidShowListener =            Keyboard.addListener('keyboardDidShow', this.keyboardDidShow);
  return function clearSubscription() {
      this.keyboardDidShowListener.remove();
    };
  });
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

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

React применит все эффекты, используемые компонентом, в том порядке, в котором они были указаны.

  • Оптимизация производительности за счет пропуска эффектов -
    Очистка или применение эффекта после каждого рендеринга в некоторых случаях может вызвать проблемы с производительностью. Чтобы противостоять этому, вы можете указать React пропустить применение эффекта, если определенные значения не изменились между повторными рендерингами. Для этого передайте массив в качестве второго необязательного аргумента в useEffect.
useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes

Если вы хотите запустить эффект и очистить его только один раз (при монтировании и размонтировании соответственно), вы можете передать пустой массив ([]) в качестве второго аргумента. Это сообщает React, что ваш эффект не зависит от каких-либо значений свойств или состояния, поэтому его никогда не нужно запускать повторно.

Другие хуки

Есть несколько других хуков, таких как useContext, который предоставляет контекст в функциональном компоненте, и некоторые другие дополнительные хуки, о которых мы поговорим в следующем посте. Если вам интересно, можете перейти по этой ссылке.

Что нужно помнить при использовании крючков

При использовании хуков необходимо знать несколько правил.

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

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

Заключение

Хуки - это потрясающая мощная функция, которая появится в V16.7. Они предоставляют нам возможности классов без необходимости их расширения. Я предлагаю всем поиграть с ними.
Они станут будущим того, как мы будем делать наши компоненты, зависящие от жизненного цикла с отслеживанием состояния, в будущем.
Надеюсь, вам понравилась эта статья. Спасибо за чтение.

Это моя первая статья о средних, предложения приветствуются :)

Ссылка

Https://reactjs.org/docs/hooks-reference.html