React Memo
React.memo— это компонент высшего порядка (HOC), используемый для оптимизации производительности функциональных компонентов. Он повышает производительность за счёт мемоизации выходных данных рендеринга компонента и пропуска повторных рендеров, когда пропсы компонента не изменились. Ниже приводитсяReact.memoподробное введение и методы использования.
1. Базовое использование
React.memoОсновное использование — передать функциональный компонент в качестве аргумента вReact.memo, и вернуть мемоизированный компонент.
Пример
import ReactDOM from 'react-dom';
const MyComponent = React.memo((props) => {
console.log('Rendering MyComponent');
return <div>{props.text}</div>;
});
const App = () => {
const [count, setCount] = React.useState(0);
const [text, setText] = React.useState('Hello, world!');
return (
<div>
<button onClick={() => setCount(count + 1)}>Увеличить счётчик</button>
<MyComponent text={text} />
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
В этом примере, даже еслиcountсостояние изменяется,MyComponentон не будет повторно рендериться, потому что егоpropsне изменилось.
2. Использование пользовательской функции сравнения
По умолчанию,React.memoсравнивает только предыдущие и следующиеprops, и если изменений нет, он не будет повторно рендериться. Вы можете точнее управлять логикой повторного рендеринга, передав пользовательскую функцию сравнения.
Сигнатура пользовательской функции сравнения:
function areEqual(prevProps, nextProps) {
// 返回 true 表示相等,不需要重新渲染
// 返回 false 表示不相等,需要重新渲染
}
Пример
import ReactDOM from 'react-dom';
const MyComponent = React.memo((props) => {
console.log('Rendering MyComponent');
return <div>{props.text}</div>;
}, (prevProps, nextProps) => {
return prevProps.text === nextProps.text;
});
const App = () => {
const [count, setCount] = React.useState(0);
const [text, setText] = React.useState('Hello, world!');
return (
<div>
<button onClick={() => setCount(count + 1)}>Увеличить счётчик</button>
<MyComponent text={text} />
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
В этом примере пользовательская функция сравнения проверяетtextизменилось ли оно. Еслиtextне изменилось,MyComponentон не будет повторно рендериться.
3. Практические сценарии применения
React.memoОн очень хорошо подходит для следующих сценариев:
- Отображение статических данных: props, получаемые компонентом
propsредко меняются, но сам компонент относительно сложен, и повторный рендеринг обходится дорого. - Оптимизация производительности: В больших списках или таблицах каждый элемент является независимым компонентом, с помощью
React.memoможно избежать ненужных повторных рендеров. - Избегайте глубоких проверок равенства: пользовательская функция сравнения позволяет избежать глубоких проверок равенства, особенно когда
propsсодержит большой объем данных.
4. Примечания
- Поверхностное сравнение: По умолчанию,
React.memoвыполняет поверхностное сравнение, то есть сравнивает толькоpropsсодержимое верхнего уровня. Вложенные объекты требуют пользовательской функции сравнения. - Состояние и контекст:
React.memoучитывает толькоpropsизменения. Изменения внутреннего состояния компонента и контекста не будут вызывать повторный рендеринг.
5. С помощьюuseMemoиuseCallbackразница
React.memo: используется для мемоизации всего компонента и оптимизации рендеринга компонента.useMemo: используется для мемоизации значений или вычисленных результатов внутри функциональных компонентов.useCallback: используется для мемоизации функций обратного вызова внутри функциональных компонентов, чтобы избежать ненужного повторного создания.
Пример
import ReactDOM from 'react-dom';
const ChildComponent = React.memo(({ onClick, count }) => {
console.log('Rendering ChildComponent');
return <button onClick={onClick}>Count: {count}</button>;
});
const App = () => {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount(count + 1);
}, [count]);
const doubledCount = useMemo(() => count * 2, [count]);
return (
<div>
<p>Удвоенное количество: {doubledCount}</p>
<ChildComponent onClick={increment} count={count} />
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
В этом примере,useCallbackиuseMemoиспользуется для оптимизации функций и вычисляемых результатов,React.memoиспользуется для оптимизации рендеринга дочерних компонентов.
Итог
React.memo— мощный инструмент, который может эффективно повысить производительность функциональных компонентов и избежать ненужных повторных рендеров. ИспользуяReact.memoи пользовательские функции сравнения, вы можете значительно оптимизировать производительность приложения, не влияя на логику приложения.