從 useMemo 一步步
理解 react 性能優化
1. 與 useMemo 的第一次相遇
2. 關於 render 的那些事
3. 如何性能優化
4. Immutable
5. React.memo 等於 useMemo ?
與 useMemo 的第一次相遇
...
const saveBtn = useMemo(() => (
<button
style={{
...styles.syncBtn,
...(dirty && !submitting ? styles.synbBtnDirty : {}),
}}
onClick={syncToServer}
type="button">
{submitting ? <LoadingSpinner /> : '儲存'}
</button>
), [dirty, submitting, syncToServer]);
...
查了一下官方文件,它是這麼說的
Returns a memoized value.
Pass a “create” function and an array of dependencies. useMemo will only recompute the memoized value when one of the dependencies has changed. This optimization helps to avoid expensive calculations on every render.
恩......怎麼看起來跟 useEffect 87% 像
雖然研究的時候發現自己拐很多彎.......
不過還是幫助我釐清了一些觀念
應該啦ˊ_>ˋ
什麼是 render
class Foo extends React.Component {
render() {
return <h1> Foo </h1>;
}
}
function Foo() {
return <h1> Foo </h1>;
}
React 的渲染機制 - 1
即使狀態沒變化,只要調用了setState 就會觸發 render
parent
component
對函數式組件來說,狀態值改變時才會觸發 render 函數的調用。
無論是 functional 或 Class ,一但父層重新render,子層的 render 都會被觸發
React 的渲染機制 - 2
實際上 React 怎麼把畫面渲染出來的?
- render function
- virtual DOM diff
- Reconciliation
詳情可以看 => 把哺的簡報
回到上頁,我們有沒有優化的可能性?
- render function
- virtual DOM diff
- Reconciliation
提升 React 效能
如果你已經預期這個 component 不會被頻繁的更新
- render function
- virtual DOM diff
- Reconciliation
不要觸發它的 render function
因為就算 virtual DOM diff 很快
不 diff 還是更快呀ˊ_>ˋ
shouldComponentUpdate
shouldComponentUpdate
- shouldComponentUpdate
- render function
- virtual DOM diff
可以讓我們在 render 前多做一個檢查
class Content extends React.Component {
shouldComponentUpdate(){
return false
}
render () {
return <div>{this.props.text}</div>
}
}
像這樣這個 component
就永遠不會重新 render ˊ_>ˋ
class Content extends React.Component {
shouldComponentUpdate(nextProps, nextState){
return !shallowEqual(this.props, nextProps)
|| !shallowEqual(this.state, nextState);
}
render () {
return <div>{this.props.text}</div>
}
}
所以實務上會是如此 shallow compare
shallowEqual
=> 可以理解成修正 js 一些怪異bug的 "===" 比較
=> 只比較一層,所以在比較 Object 時有可能會發生錯誤
NaN === NaN // false
+0 === -0 // true
Immutable
記得一開始學都被說要這樣寫
this.setState({
obj: {
...this.state.obj,
id: 2
}
})
this.setState({
list: [...this.state.arr, 123]
})
// 不能這樣
const newObject = this.state.obj
newObject.id = 2;
this.setState({
obj: newObject
})
// 也不能這樣
const arr = this.state.arr;
arr.push(123);
this.setState({
list: arr
})
不過每次都寫 shouldComponentUpdate 很累,因此有了 PureComponent, React.memo
class Row extends PureComponent {
render () {
.....
}
}
const Demo = React.memo(({ children }) => <div>{children}</div>);
但這樣是不是全部 component 都用 pureComponent 或 React.memo 就讚讚?
不是,因為若是你這個 component 會頻繁更新,你這樣反而每次都會多算一次 shallowCompare
其實更不划
所以 useMemo 等於 React.memo?
下集預告:Memoization
參考資料
7/11 從 useMemo 一步步 理解 react 性能優化
By Jay Chou
7/11 從 useMemo 一步步 理解 react 性能優化
- 328