React

Использование хуков React дает множество полезных преимуществ. Узнаем, что такое жизненные циклы React и рассмотрим реализацию этих циклов с помощью Reason React Hooks.

После выпуска Reason React Hooks многие разработчики обновили базу кода для поддержки хуков. Сообщество Reason react также предоставило сценарий для обновления, однако он просто оборачивает существующий компонент с помощью ReasonReactCompact.wrapReasonReactForReact для перехвата компонентов. Он не добавляет логику для хуков, поскольку это зависит от случая использования, а также между обоими компонентами нет прямого отображения.

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

React Hooks

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

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

С помощью хуков можно использовать логику с состоянием повторно без изменения иерархии компонентов. Благодаря этому можно легко обмениваться хуками между компонентами или сообществом.

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

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

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

Жизненные циклы React

К каждому компоненту react прикреплен цикл, начиная от его создания до удаления внутри DOM. В течение этого цикла вызывается несколько методов в соответствии с различными стадиями компонента. Этот цикл называется жизненным циклом компонента React и он разделен на 4 этапа:

  • Инициализация
  • Монтирование
  • Обновление
  • Размонтирование

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

Методы жизненного цикла, вызываемые при инициализации компонента

На этой стадии устанавливаются начальные свойства компонента. Здесь можно определить состояние, установить props по умолчанию и многое другое. Ниже приведены методы, которые вызываются на этой стадии.

  • constructor — этот метод жизненного цикла вызывается перед рендером и используется для инициализации состояния или создания привязок для прослушивателя событий, который будет использовать компонент.
type state = { counter: int };

// Присваивание начального состояния в методе constructor
let initialState = () => { counter: 0 };

[@react.component]
let make = () => {
  let (state, setState) => React.useState(initialState);
  
  "initial state is set using hooks" -> React.string;
};

Методы жизненного цикла, вызываемые при монтировании компонента

Ниже приведены методы жизненного цикла, которые вызываются при создании или вставке компонента в DOM.

  • render — этот метод жизненного цикла используется для создания HTML-содержимого для следующего компонента. Эта функция возвращает элементы React, которые затем преобразуются в элементы DOM. Они должны быть чистой функцией и не должны изменять состояние при возврате элементов. Ознакомиться с подробной информацией о чистых функциях можно здесь.
[@react.component]
let make = (~name) => {
  // все тело этого метода входит в жизненный цикл рендера
  
  name -> React.string;
};
  • componentDidMount— этот метод жизненного цикла вызывается для извлечения данных или манипулирования DOM после рендеринга компонента. Обновить состояние можно на основе вычислений, выполненных в этом методе. Этот метод вызывается только после первого рендеринга компонента, для последующего рендеринга понадобятся другие методы жизненного цикла.
[@react.component]
let make = (~name: string) => {
  let (counter, setCounter) = React.useState(() => 0);
  
  // Введите что угодно в componentDidMount.
  React.useEffect1(
    () => {
      setCounter(_ => counter + 1);
      None
    },
    [||] // Это ключ, поскольку он не будет зависеть от изменений props.
  );
  
  "counter is rendered only 1 time" -> React.string;
}

Методы жизненного цикла, вызываемые при обновлении компонента

Ниже перечислены методы жизненного цикла, которые вызываются при каждом изменении состояния или props. Эти методы жизненного цикла вызываются при каждом повторном рендеринге.

  • shouldComponentUpdate — этот метод жизненного цикла вызывается, чтобы определить, будет ли выполнен повторный рендеринг компонента при изменении props или состояния компонентов путем возврата логического флага. По умолчанию компонент будет выполнять повторный рендеринг при каждом изменении состояния или prop.
[@react.component]
let make = (~name) => name -> React.string;

// Для выполнения shallow-сравнения props используйте React.memo
let make = React.memo(make);

// Для выполнения custom-сравнения вложенных props используйте React.memoCustomCompareProps
let deepCompare = (nextProps, currentProps) => nextProps === currentProps;

let make = React.memoCustomCompareProps(
  make,
  (nextProps, currentProps) => {
    let result = deepCompare(nextProps, currentProps);
    result;
  }
);

Примечание: также можно использовать React.useMemo для создания memoized-функций, чтобы компонент не визуализировался после того, как сложное вычисление возвратит тот же результат.

  • componentDidUpdate — этот метод жизненного цикла вызывается после каждого повторного рендеринга, кроме первого. Этот жизненный цикл обычно используется для выполнения любых вычислений, например, сетевые запросы, прослушиватель событий на основе изменений в props. Обязательно сравнивайте props при обновлении состояния, иначе повторный рендеринг будет выполняться бесконечно.
[@react.component]
let make = (~name, ~) => {
  let (counter, setCounter) => React.useState(() => 0);
  
  // Изменение состояния/props допускается только в том случае, если определенные props переданы или изменены.
  React.useEffect1(
    () => {
      if (name === "componentDidUpdate") {
        setCounter(_ => counter + 1);
        None
      }
    },
    [|name|] // Здесь перечислена зависимость от того, какой компонент будет выполнять повторный рендеринг.
  );
  
  (name ++ "is called " ++ counter -> string_of_int ++ " times.") -> React.string;
};

Методы жизненного цикла, вызываемые при размонтировании компонента

Эти методы жизненного цикла вызываются при удалении компонента из DOM.

  • componentWillUnmount — этот метод жизненного цикла вызывается для выполнения очистки, например, удаление подписок или прослушивателей событий в компоненте, только перед размонтированием компонента.
[@react.component]
let make = () => {
  let (counter, setCounter) = React.useState(() => 0);
  
  React.useEffect(() => {
    let clearTimeout = Js.Global.setTimeout(() => setCounter(_ => counter + 1), 500);
    
    Some(Js.Global.clearTimeout(clearTimeout)) // Этот метод будет вызван при размонтировании компонента
  });
  ("Counter is updated " ++ counter -> string_of_int ++ " times.") -> React.string;
};

Методы жизненного цикла для обработки ошибок в компонентах

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

Заключение

Выше приведено краткое руководство по переходу от ReasonReact.reactClass (тип компонента Reason React до появления хуков) к React.Element (обновленный компонент Reason React, реализующий хуки). Узнать больше информации о хуках можно здесь, а здесь перечислено множество других хуков. Сообщество open source приступило к созданию пользовательских хуков для решения общих проблем. Вы также можете создать собственные (больше информации об этом здесь).

Спасибо за внимание 🙂


Перевод статьи Nimish Gupta: Implementing React Life Cycles Using Reason React Hooks