2個奇怪的React寫法

卡頌發表於2023-03-14

大家好,我卡頌。

雖然React官網用大量篇幅介紹最佳實踐,但因JSX語法的靈活性,所以總是會出現奇奇怪怪的React寫法。

本文介紹2種奇怪(但在某些場景下有意義)的React寫法。也歡迎大家在評論區討論你遇到過的奇怪寫法。

歡迎加入人類高質量前端交流群,帶飛

ref的奇怪用法

這是一段初看讓人很困惑的程式碼:

function App() {
  const [dom, setDOM] = useState(null);
 
  return <div ref={setDOM}></div>;
}

讓我們來分析下它的作用。

首先,ref有兩種形式(曾經有3種):

  1. 形如{current: T}的資料結構
  2. 回撥函式形式,會在ref更新、銷燬時觸發

例子中的setDOMuseStatedispatch方法,也有兩種呼叫形式:

  1. 直接傳遞更新後的值,比如setDOM(xxx)
  2. 傳遞更新狀態的方法,比如setDOM(oldDOM => return /* 一些處理邏輯 */)

在例子中,雖然反常,但ref的第二種形式和dispatch的第二種形式確實是契合的。

也就是說,在例子中傳遞給refsetDOM方法,會在div對應DOM更新、銷燬時執行,那麼dom狀態中儲存的就是div對應DOM的最新值。

這麼做一定程度上實現了感知DOM的實時變化,這是單純使用ref無法具有的能力。

useMemo的奇怪用法

通常我們認為useMemo用來快取變數propsuseCallback用來快取函式props

但在實際專案中,如果想透過快取props的方式達到子元件效能最佳化的目的,需要同時保證:

  • 所有傳給子元件的props的引用都不變(比如透過useMemo
  • 子元件使用React.memo

類似這樣:

function App({todos, tab}) {
    const visibleTodos = useMemo(
      () => filterTodos(todos, tab),
    [todos, tab]);
    
    return <Todo data={visibleTodos}/>;
}

// 為了達到Todo效能最佳化的目的
const Todo = React.memo(({data}) => {
  // ...省略邏輯
})

既然useMemo可以快取變數,為什麼不直接快取元件的返回值呢?類似這樣:

function App({todos, tab}) {
  const visibleTodos = useMemo(
      () => filterTodos(todos, tab),
  [todos, tab]);
  
  return useMemo(() => <Todo data={visibleTodos}/>, [visibleTodos])
}

function Todo({data}) {
  return <p>{data}</p>;
}

如此,需要效能最佳化的子元件不再需要手動包裹React.memo,只有當useMemo依賴變化後子元件才會重新render

總結

除了這兩種奇怪的寫法外,你還遇到哪些奇怪的React寫法呢?

相關文章