React 性能优化:如何避免乱用缓存带来的问题

前言

在之前的文章中,我列举了一些 React 常用的 Hooks。其中一些 Hooks 如 React.memo,useMemo 等 hooks 可以缓存结果,但是这不代表我们可以无脑的缓存,因为内存的开销也是很昂贵的。

组件化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import React from "react";

const Expensive = () => {
console.log("expensive compenent rendered!");

let total = 0;
for (let i = 0; i < 1000000000; i++) {
total += i;
}

return <div>Expensive</div>;
};

export default Expensive;

// const Expensive = React.memo(() => {
// console.log("expensive compenent rendered!");

// let total = 0;
// for (let i = 0; i < 1000000000; i++) {
// total += i;
// }

// return <div>Expensive</div>;
// });

// export default Expensive;

组件之间分开,规避状态改变重新渲染组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { useEffect, useMemo, useState } from "react";
import Expensive from "./Expensive";

function App4() {
// const [name, setName] = useState("");

// return (
// <div>
// <input onChange={(e) => setName(e.target.value)} placeholder="name" />
// <Expensive />
// </div>
// );
// }

return (
<div>
<Form />
<Expensive />
</div>
);
}

const Form = () => {
const [name, setName] = useState("");
return <input onChange={(e) => setName(e.target.value)} placeholder="name" />;
};

export default App4;

这样的话,form 表单改变也不会说重新导致 Expensive 组件的渲染

父子组件交换数据

那么如果父组件又需要子组件的值呢,子组件改变值,也会导致其他子组件改变。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import { useEffect, useMemo, useState } from "react";
import Expensive from "./Expensive";

function App5() {
// const [backgroundColor, setBackgroundColor] = useState("white");

// return (
// <div style={{ backgroundColor }}>
// <input onChange={(e) => setBackgroundColor(e.target.value)} />
// <Expensive />
// </div>
// );

return (
<BgProvider>
<Expensive />
</BgProvider>
);
}

const BgProvider = ({ children }) => {
let [backgroundColor, setBackgroundColor] = useState("white");
return (
<div style={{ backgroundColor }}>
<input onChange={(e) => setBackgroundColor(e.target.value)} />
{children}
</div>
);
};

export default App5;

我们可以通过组件之间的包裹,来完成。这样的话 children 由于没有改变所以不大会导致重新渲染