предисловие
Поскольку функциональные компоненты React проще в использовании (по сравнению с классовыми компонентами), я сосредоточусь на использовании функциональных компонентов для запуска разработки. В этой серии блогов я поделюсь тем, что узнал об API серии Hook. Серия крючков в основном делится на следующие:
Memo
В эпоху классов мы обычно используем pureComponent для поверхностного сравнения данных.После введения функции Hook мы можем использовать Memo для повышения производительности.
Перед этим проведем эксперимент
import React, { useState } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const [n, setN] = useState(0);
const [m, setM] = useState(10);
console.log("执行最外层盒子了");
return (
<>
<div>
最外层盒子
<Child1 value={n} />
<Child2 value={m} />
<button
onClick={() => {
setN(n + 1);
}}
>
n+1
</button>
<button
onClick={() => {
setM(m + 1);
}}
>
m+1
</button>
</div>
</>
);
}
function Child1(props) {
console.log("执行子组件1了");
return <div>子组件1上的n:{props.value}</div>;
}
function Child2(props) {
console.log("执行子组件2了");
return <div>子组件2上的m:{props.value}</div>;
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
В приведенном выше коде я настроил два подкомпонента, соответственно прочитал n и m в родительском компоненте, а затем установил две кнопки щелчка в родительском компоненте.При нажатии добавляю 1 к набору n и m соответственно. Вот результат лог-консоли при первом рендеринге
执行最外层盒子了
执行子组件1了
执行子组件2了
Как и предполагалось, при рендеринге сначала введите функцию приложения, выполните, найдите две дочерние функции внутри, выполните, создайте виртуальный дом, создайте объектный дом и, наконец, отобразите экран на странице.
Оптимизируйте с помощью Memo
Когда я нажимаю кнопку n+1, в это время n в состоянии должно быть +1, что также снова запускает рендеринг и обновляет новое n в представлении.Посмотрим еще раз на консоль
执行最外层盒子了
执行子组件1了
执行子组件2了
+ 执行最外层盒子了
+ 执行子组件1了
+ 执行子组件2了 //为什么组件2也渲染了,里面的m没有变化
Вы обнаружите, что также отображается подкомпонент 2. Очевидно, что react повторно выполняет все функции снова и повторно выполняет подкомпонент 2, у которого нет данных n.
Как оптимизировать? мы можем использоватьmemo
Измените дочерний компонент на следующий код
const Child1 = React.memo((props) => {
console.log("执行子组件1了");
return <div>子组件1上的n:{props.value}</div>;
});
const Child2 = React.memo((props) => {
console.log("执行子组件2了");
return <div>子组件2上的m:{props.value}</div>;
});
Нажмите еще раз, чтобы попробовать?
执行最外层盒子了
执行子组件1了
执行子组件2了
+ 执行最外层盒子了
+ 执行子组件1了
Вы обнаружите, что подкомпонент 2 не выполняется.
В этом случае react выполнит только компонент, соответствующий изменению состояния, а компонент, который не изменился, будет повторно использовать последнюю функцию.Может быть, memo также означает память, что означает запоминание последней функции, а не ее повторное выполнение (я предполагаю - -!!)
ошибка
Хотя приведенный выше код был оптимизирован для повышения производительности, в нем будет ошибка
Приведенный выше код контролируется родительским компонентом.<button>
Да, а если я передам функцию, контролирующую состояние, дочернему компоненту?
<Child2 value={m} onClick={addM} /> //addM是修改M的函数
Нажмите кнопку, чтобы разрешить n+1
执行最外层盒子了
执行子组件1了
执行子组件2了
+ 执行最外层盒子了
+ 执行子组件1了
+ 执行子组件2了
Подкомпонент 2 выполняется снова.
Почему это происходит? Поскольку приложение выполняется повторно, оно изменит адрес функции addM (функция представляет собой сложный тип данных), а addM будет передан подкомпоненту 2 в качестве реквизита, что вызовет повторное выполнение подпрограммы. -функция компонента 2.
useMemo
В настоящее время для решения проблемы следует использовать useMemo.
useMemo(()=>{},[])
useMemo получает два параметра, функцию и массив (фактически зависимость), возвращаемую функцию в функции и зависимость в массиве.
const addM = useMemo(() => {
return () => {
setM({ m: m.m + 1 });
};
}, [m]); //表示监控m变化
Способ его использования аналогичен useEffect.
useCallback
Код выше очень странный
useMemo(() => {
return () => {
setM({ m: m.m + 1 });
};
}, [m])
React подготовил для нас синтаксический сахар, используйте Callback. это написано так
const addM = useCallback(() => {
setM({ m: m.m + 1 });
}, [m]);
Выглядит более нормально?
окончательный код
import React, { useCallback, useMemo, useState } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const [n, setN] = useState(0);
const [m, setM] = useState({ m: 1 });
console.log("执行最外层盒子了");
const addN = useMemo(() => {
return () => {
setN(n + 1);
};
}, [n]);
const addM = useCallback(() => {
setM({ m: m.m + 1 });
}, [m]);
return (
<>
<div>
最外层盒子
<Child1 value={n} click={addN} />
<Child2 value={m} click={addM} />
<button onClick={addN}>n+1</button>
<button onClick={addM}>m+1</button>
</div>
</>
);
}
const Child1 = React.memo((props) => {
console.log("执行子组件1了");
return <div>子组件1上的n:{props.value}</div>;
});
const Child2 = React.memo((props) => {
console.log("执行子组件2了");
return <div>子组件2上的m:{props.value.m}</div>;
});
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Рекомендуется копировать прямо вcodesanboxПроверить
Суммировать
- использовать
memo
может помочь нам оптимизировать производительность, пустьreact
Нет необходимости выполнять ненужные функции - Так как адрес сложного типа данных может измениться, адрес передается дочернему компоненту
props
Он также изменится, поэтому лишние функции все равно будут выполняться, поэтому он используетсяuseMemo
этот API -
useCallback
даuseMemo
синтаксический сахар для