Оптимизация производительности React приложений

месяц назад·1 мин. на чтение

В этой статье мы рассмотрим различные способы оптимизации производительности React приложений, чтобы они работали быстро и плавно.

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

1. Используйте мемоизацию с помощью useMemo или useCallback:

Мемоизация - это процесс сохранения результатов выполнения функции и использования их вместо повторного выполнения функции с одними и теми же аргументами. В функциональных компонентах React вы можете использовать хуки useMemo или useCallback для мемоизации значений или колбэков соответственно. Это позволяет избежать повторных вычислений и улучшить производительность вашего приложения.

2. Разделение компонентов на более мелкие:

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

3. Используйте React.memo:

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

4. Используйте ключи при отображении списков:

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

5. Используйте ленивую загрузку компонентов:

Ленивая загрузка позволяет разделить ваше приложение на небольшие фрагменты и загружать их по мере необходимости. Это может существенно улучшить производительность вашего приложения, особенно если у вас есть большие компоненты или много зависимостей. Вы можете использовать React.lazy и Suspense для ленивой загрузки компонентов.

6. Используйте shouldComponentUpdate или React.memo для предотвращения ненужных перерисовок:

Если вы работаете с классовыми компонентами, вы можете использовать метод shouldComponentUpdate для ручного контроля перерисовки компонента. В функциональных компонентах вы можете использовать React.memo или пользовательский хук, чтобы достичь того же результата. Это позволяет избежать ненужных перерисовок компонента, если его пропсы не изменились. В заключение, оптимизация производительности React приложений является важным аспектом разработки. С использованием мемоизации, разделения компонентов, ключей для списков, ленивой загрузки компонентов и предотвращения ненужных перерисовок, вы можете значительно улучшить производительность вашего React приложения, особенно при использовании функциональных компонентов.

Как вызвать метод дочернего компонента из родительского компонента с помощью useImperativeHandle

2 года назад·3 мин. на чтение

Быстрый старт с useImperativeHandle

В этой статье будет показано, как вызвать метод дочернего компонента с помощью ссылки. Чтобы решить эту проблему, мы будем использовать хуки useRef и useImperativeHandle.

Дочерний компонент

Начнем с простого дочернего компонента, в котором содержится кнопка. Нажатие на кнопку вызывает внутренний метод doSomething.
// Child.jsx

function Child(props, ref) {
  const doSomething = () => {
    console.log("do something");
  };
  return (
    <div>
      <h1>Child Component</h1>
      <button onClick={doSomething}>Run</button>
    </div>
  );
}

export default Child;

Родительский компонент

Далее рассмотрим родительский компонент. В нем используется дочерний компонент, описанный выше. Обратите внимание, что в родительском компоненте есть собственная кнопка сохранения.
// App.jsx

import Child from "./Child";

function App() {
  const save = () => {};
  return (
    <div>
      <Child />
      <button onClick={save}>Save</button>
    </div>
  );
}

export default App;

Хук useImperativeHandle

Теперь давайте сосредоточимся на нашей задаче. Мы хотим вызвать метод (doSomething) дочернего компонента при нажатии кнопки (Save) из родительского компонента. Чтобы вызвать метод из дочернего компонента, нам нужно сначала выставить его наружу. useImperativeHandle определяет значение объекта, которое предоставляется родительскому компоненту при использовании ref. Добавляя наш метод к этому объекту, мы делаем его доступным в родительских компонентах.
// Child.jsx

import { useImperativeHandle } from "react";

function Child(props, ref) {
  const doSomething = () => {
    console.log("do something");
  };

  useImperativeHandle(ref, () => ({ doSomething }));

  return (
    <div>
      <h1>Child Component</h1>
      <button onClick={doSomething}>Run</button>
    </div>
  );
}
export default Child;
useImperativeHandle следует использовать с forwardRef.
forwardRef позволяет родительскому компоненту передавать ссылки своим дочерним элементам. Чтобы прикрепить функции или поля к этой ссылке (к рефу), используется хук useImperativeHandle.
// Child.jsx

import { forwardRef, useImperativeHandle } from "react";

function Child(props, ref) {
  const doSomething = () => {
    console.log("do something");
  };

  useImperativeHandle(ref, () => ({ doSomething }));

  return (
    <div>
      <h1>Child Component</h1>
      <button onClick={doSomething}>Run</button>
    </div>
  );
}

export default forwardRef(Child); // Child обернут в forwardRef
На этом этапе мы можем создать ссылку в родительском компоненте с помощью хука useRef и передать ее дочернему компоненту. Получив эту ссылку, мы можем вызвать метод doSomething дочернего компонента.
// App.jsx

import { useRef } from "react";
import Child from "./Child";

function App() {
  const childRef = useRef(null);

  const save = () => {
    if (childRef.current) {
      childRef.current.doSomething();
    }
  };

  return (
    <div>
      <Child ref={childRef} />
      <button onClick={save}>Save</button>
    </div>
  );
}

export default App;

Добавим TypeScript

Далее посмотрим, какие изменения нужно сделать, чтобы вызвать тот же дочерний метод из родительского компонента при использовании TypeScript. Во-первых, нам нужно определить новый интерфейс, содержащий метод, который будет представлен.
export interface RefType {
  doSomething: () => void;
}
Затем новый тип (RefType) используется при получении ссылки в дочернем компоненте.
function Child(props: PropsType, ref: Ref<RefType>)
Ниже приведен полный код дочернего компонента.
// Child.jsx

import { forwardRef, useImperativeHandle, Ref } from "react";

export interface PropsType {}
export interface RefType {
  doSomething: () => void;
}

function Child(props: PropsType, ref: Ref<RefType>) {
  const doSomething = () => {
    console.log("do something");
  };
  useImperativeHandle(ref, () => ({ doSomething }));
  return (
    <div>
      <h1>Child Component</h1>
      <button onClick={doSomething}>Run</button>
    </div>
  );
}

export default forwardRef(Child);
В родительский компонент нам нужно импортировать этот RefType, содержащий все публичные дочерние методы, и использовать его при создании ref.
// App.jsx

import Child, { RefType } from "./Child";
//...
const childRef = useRef<RefType>(null);
Полный код родительского компонента.
import { useRef } from "react";
import Child, { RefType } from "./Child";

function App() {
  const childRef = useRef<RefType>(null);

  const save = () => {
    if (childRef.current) {
      childRef.current.doSomething();
    }
  };

  return (
    <div>
      <Child ref={childRef} />
      <button onClick={save}>Save</button>
    </div>
  );
}

export default App;