從 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 怎麼把畫面渲染出來的?

  1.  render function
  2.  virtual DOM diff 
  3.  Reconciliation

詳情可以看 => 把哺的簡報 

回到上頁,我們有沒有優化的可能性?

  1.  render function
  2.  virtual DOM diff 
  3.  Reconciliation

提升 React 效能

如果你已經預期這個 component 不會被頻繁的更新

  1.  render function
  2.  virtual DOM diff 
  3.  Reconciliation

不要觸發它的 render function

因為就算 virtual DOM diff 很快

不 diff 還是更快呀ˊ_>ˋ

shouldComponentUpdate

 shouldComponentUpdate

  1.  shouldComponentUpdate
  2.  render function
  3.  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