Мемоизация и React.memo аналоги

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


Основы мемоизации в Inferno

В Inferno компоненты могут быть функциональными или классовыми. Для функциональных компонентов мемоизация позволяет кешировать результат рендера на основе пропсов. Если пропсы остаются неизменными между рендерами, компонент не будет пересоздан, что снижает нагрузку на виртуальный DOM.

Пример функционального компонента:

import { render } from 'inferno';
import { memo } from 'inferno-memo';

const Button = ({ label, onClick }) => {
    console.log('Button render');
    return <button onCl ick={onClick}>{label}</button>;
};

const MemoizedButton = memo(Button);

render(<MemoizedButton label="Click me" onCl ick={() => console.log('Clicked')} />, document.getElementById('app'));

В данном примере memo оборачивает компонент Button и предотвращает его повторный рендер, если label и onClick остаются неизменными.


Сравнение с React.memo

Механизм memo в Inferno схож с React.memo и выполняет аналогичные функции:

  • Сравнение пропсов по умолчанию — поверхностное сравнение объектов. Если пропсы не изменились, компонент не перерисовывается.
  • Кастомная функция сравнения — позволяет определить более сложную логику, например сравнение вложенных объектов или массивов.

Пример кастомной функции сравнения:

const areEqual = (prevProps, nextProps) => {
    return prevProps.label === nextProps.label && prevProps.value === nextProps.value;
};

const CustomMemoButton = memo(Button, areEqual);

Мемоизация вычислений внутри компонентов

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

Пример мемоизации вычислений:

import { useMemo } from 'inferno-hooks';

const ExpensiveComponent = ({ data }) => {
    const processedData = useMemo(() => {
        console.log('Processing data');
        return data.map(item => item * 2);
    }, [data]);

    return <div>{processedData.join(', ')}</div>;
};

В этом примере processedData пересчитывается только тогда, когда изменяется массив data.


Мемоизация событий и коллбеков

Частая проблема производительности — создание новых функций при каждом рендере. В Inferno можно использовать useCallback для мемоизации коллбеков, аналогично React:

import { useCallback } from 'inferno-hooks';

const Counter = () => {
    const [count, setCount] = useState(0);

    const increment = useCallback(() => {
        setCount(prev => prev + 1);
    }, []);

    return <button onCl ick={increment}>{count}</button>;
};

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


Оптимизация классовых компонентов

Для классовых компонентов мемоизация осуществляется с помощью shouldComponentUpdate или PureComponent. PureComponent автоматически выполняет поверхностное сравнение пропсов и состояния:

import { Component, render } from 'inferno';

class Button extends Component {
    shouldComponentUpdate(nextProps) {
        return this.props.label !== nextProps.label;
    }

    render() {
        console.log('Button render');
        return <button onCl ick={this.props.onClick}>{this.props.label}</button>;
    }
}

Использование shouldComponentUpdate или PureComponent позволяет контролировать ререндер на уровне классового компонента.


Практические рекомендации

  1. Мемоизировать только “тяжелые” компоненты. Легкие компоненты без сложной логики обычно не требуют оптимизации.
  2. Использовать кастомные функции сравнения при работе со сложными пропсами (объекты, массивы).
  3. Комбинировать useMemo и memo для максимального снижения лишних ререндеров.
  4. Следить за созданием коллбеков и мемоизировать их через useCallback для передачи в дочерние компоненты.
  5. Профилировать приложение перед оптимизацией — мемоизация без необходимости может усложнять код без заметного прироста производительности.

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