React 笔记(性能优化篇)
1. useState
useState
的参数可以传入一个函数,这样就可以避免每次更新时都重新创建一个对象。
import React, { useState } from 'react';
function App() {
const [expensiveValue, setExpensiveValue] = useState(() => {
console.log('初始化 state');
return Array(1000000).fill(0).map(() => Math.random())
})
return (
<div>
<p>数组长度: {expensiveValue.length}</p>
<button onClick={() => setExpensiveValue([...expensiveValue, Math.random()])}>添加一个随机数</button>
</div>
)
}
export default App;
上述代码中,console.log
只会在首次渲染时执行一次,后续更新时不会重新执行。
2. useMemo
使用 useMemo
缓存比较消耗性能的操作,比如生成二维码,避免在每次渲染时都进行重复的计算。
import React, { useMemo, useState } from 'react';
import QRCode from 'qrcode.react';
function App() {
const [text, setText] = useState("Hello, world!");
const memoizedQRCode = useMemo(() => {
return <QRCode value={text} />;
}, [text]); // 只有当 text 改变时才重新生成二维码
return (
<div>
<input
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
/>
{memoizedQRCode}
</div>
);
}
export default App;
上述代码中,memoizedQRCode
只有在 text
改变时才会重新生成二维码,从而避免每次渲染时都重新生成二维码。
3. useCallback
使用 useCallback
缓存函数,避免在每次渲染时都重新创建函数。
import React, { useState, useCallback } from 'react';
function IncrementButton({ onClick }) {
console.log('渲染 IncrementButton');
return <button onClick={onClick}>Increment</button>;
}
function App() {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount(count + 1);
}, [count]); // 缓存函数,只有 count 改变时才重新创建
return (
<div>
<p>Count: {count}</p>
<IncrementButton onClick={increment} />
</div>
);
}
export default App;
上述代码中,使用 useCallback
缓存了 increment
函数,从而避免在每次渲染时都重新创建函数。
4. memo
使用 memo
缓存组件,避免在每次渲染时都重新渲染组件,只有当组件的 props 改变时才会重新渲染组件。
import React, { memo } from 'react';
function MyComponent({ data }) {
console.log('渲染 MyComponent');
return <div>{data}</div>;
}
const MemoizedComponent = memo(MyComponent);
function App() {
return <MemoizedComponent data="Hello, world!" />
}
export default App;
上述代码中,MemoizedComponent
只有在 data
改变时才会重新渲染组件,从而避免每次渲染时都重新渲染组件。
5. useRef
使用 useRef
缓存 DOM 元素,避免在每次渲染时都重新获取 DOM 元素。
import React, { useRef } from 'react';
function App() {
const inputRef = useRef(null);
return <input ref={inputRef} />
}
export default App;
上述代码中,inputRef
只会在首次渲染时创建,后续更新时不会重新创建。
6. 路由懒加载
使用 React.lazy
和 Suspense
进行路由懒加载,避免在每次渲染时都加载组件,只有当路由改变时才会加载组件,同时 Suspense
组件可以提供 fallback 组件,避免在加载组件时出现白屏。
import React, { lazy, Suspense } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
const Home = lazy(() => import('./Home'));
const About = lazy(() => import('./About'));
function App() {
return (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
</Switch>
</Suspense>
</Router>
);
}
export default App;
上述代码中,Home
和 About
只有在路由改变时才会加载组件;在打包时,Home
和 About
会被打包成单独的文件,减少 bundle
文件的大小,提高首屏加载速度。