React Hooks и WebPython | OTUS

Курсы

Курсы в разработке Подготовительные курсы
Работа в компаниях Компаниям Блог +7 499 110-61-65

React Hooks и WebPython

WebDeb_Deep_2.4_site-5020-70d6db.png

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

Перед тем как рассматривать, что это такое, вспомним немного, как можно писать компоненты React.

    import React from 'react';

    class Welcome extends React.Component {
      render() {
        return <h1>Hello, {this.props.name}</h1>;
      }
    }

Данный компонент является тем, что называется stateless, — у него отсутствует, что называется state, — любые данные, которые свойственны конкретному компоненту, которые меняются по собственному желанию.

Такие stateless-компоненты можно переписать в стрелочном виде:

    import React from 'react';

    const Welcome = ({name}) => <h1>Hello, {name}</h1>;

Как можно увидеть, писать такие stateless-компоненты в стрелочном виде — огромное удовольствие. Но что делать с компонентами, которые имеют состояние? Например, с таким:

    import React from 'react';

    class Example extends React.Component {

      // Да, класс написан без наворотов babel  это для лучшего понимания ;)
      constructor(props) {
        super(props);
        this.state = { count: 0 };
      }

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

Обратите внимание, что для того, чтобы реализовать подобное состояние, необходимо: - проинициализировать начальное значение в конструкторе; - хранить этот count в state; - получать значение этого count в render; - и писать всё время this.setState(...), чтобы вызывать re-render при изменении state.

И это ещё простой пример! В действительности код может быть куда сложнее, как минимум, с вынесенным методом изменения состояния.

Разберёмся, как этот компонент переписать с помощью React Hooks:

    import React, { useState } from 'react';

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

Обратите внимание, компонент написан в виде стрелочной функции.

useState

Итак, useState:

    // Данная функция принимает начальное значение поля и возвращает специальный массив
    ... = useState(0);

Что возвращает:

    // useState возвращает массив из двух элементов  текущее состояние поля стейта
    // а ещё специальный метод  чтобы изменять состояние этого поля
    const [count, setCount] = useState(0);

Обратите внимание, что мы можем называть переменные для значения и метода, как хотим:

    // Это всё корректно
    const [count, setCount] = useState(0);
    const [countValue, changeCount] = useState(0);
    const [c, updateCounter] = useState(0);
    const [userName, setUserName] = useState('Masha');

А дальше пользоваться этой переменной и методом можно вот таким образом:

    <!-- Вот здесь просто вывели значение переменной -->
    <p>You clicked {count} times</p>

    <!-- А вот здесь просто вызываем в обработчике -->
    <button onClick={() => setCount(count + 1)}>

А что будет, если мы напишем несколько хуков?

    const [count, setCount] = useState(0);
    const [userName, setUserName] = useState('Masha');

Как ни странно, state не склеит эти два поля, и они будут изолированы. Как useState определит, что это два разных поля? Это просто — по порядку вызова. Ну, т. е. первый вызов useState вернёт значение и метод для “первого” поля, второй — значение и методы для “второго” и т. д.

Поэтому вводятся логичные практики: 1. Использовать хуки в корне компонента. 2. Не использовать хуки в циклах.

Собственно, всё. Подведём промежуточные итоги: 1. Мы теперь можем писать компоненты со state и в стрелочном виде. 2. useState инициализирует поле state начальным значением. 3. useState берёт на себя обязанности по хранению поля state. 4. useState оборачивает вызов setState и предоставляет более удобный метод для изменения значения. Поэтому компонент обновится.

Да и, разумеется, хуки нужно использовать только в функциональных компонентах.

useEffect и другие

Но и это не всё!

Если мы хотим делать что-то дополнительное при обновлении компонента, то классический способ выглядел бы следующим образом:

    import React from 'react';

    class Example extends React.Component {

      constructor(props) {
        super(props);
        this.state = { count: 0 };
      }

      // вызываем callback на начальном значении
      componentDidMount() {
        const { onNewValue } = this.props;
        onNewValue(this.state);
      }

      // вызываем callback при изменении значения
      componentDidupdate() {
        const { onNewValue } = this.props;
        onNewValue(this.state);
      }

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

Обратите внимание, что помимо длинного кода, мы ещё и получили необходимость перегружать два метода: componentDidMount чтобы обновить данные на первом рендере и componentDidUpdate чтобы обновить данные при последующих рендерах.

Всё это можно объединить, используя хук useEffect:

    import React, { useState } from 'react';

    const Example = ({onNewValue})  => {
      const [count, setCount] = useState(0);

      // Функция в аргументе вызовется на componentDidMount и componentDidUpdate
      useEffect(() => onNewValue(count));

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

useEffect — это и есть способ задать componentDidMount и componentDidUpdate разом.

Помимо всего прочего — useRef, useReducer, useContext, useCallback и useMemo. Ну и оставим читателям возможность самостоятельно изучить, как писать собственные хуки.

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться