React Class-based vs Functional Component 從特性淺談兩種寫法之異同

Lin Yen-Cheng on 2020-02-02 5 min. read

簡介

React 要寫出一個元件,有 Class-based 或是 Functional 兩種方式,這篇文章會從特性去淺談 React 元件兩種寫法的差異,結論先直接推薦 Functional 的方式。

下面示範了同樣的功能,但兩種不同的寫法,可以發現 Class-based 多了 extends 的寫法,白話就是編譯過後的程式碼會比較多行,Functional 則是使用接近原生的寫法,編譯後只有渲染 JSX 時需要叫用 react 提供的函式。

// Class-based
class Welcome extends React.Component {
  render() {
    return <h1>Hello, &#123;this.props.name&#125;</h1>;
  &#125;
&#125;

// Functional
function Welcome(props) &#123;
  return <h1>Hello, &#123;props.name&#125;</h1>;
&#125;

Class-based 元件

適合實作較複雜且有 side effect 的元件,元件特性如下:

  • 元件有內部狀態
  • 多種元件週期可以進行操作

React 在狀態改變的時候,有可能會把 setState 的動作 batch 起來,所以建議使用 callback 的 function 去設定。

this.setState((state, props) => (&#123;
  counter: state.counter + props.increment,
&#125;));

PureComponent

PureComponent 其實就是 Pure Function 的進階版,React 幫我們實作了 shouldComponentUpdate() 的內容來優化。概念是確定餵進去相同的 state 跟 props 每次渲染出來的畫面都是一樣的,我們就認為這個是沒有副作用的元件。

PS: 因為只做 shallowly compares,所以狀態盡量不要使用物件去存。

Functional 元件

React Hooks 加入前,Functional 的元件適合實作較純渲染的元件,元件特性如下,早期如果想寫這樣的元件,架構上就會提早做規劃也會切得比較乾淨。

  • 不包含元件狀態
  • 無法操作元件週期

React Hooks 加入後,Functional 的寫法就開始熱門了起來,因為開始可以透過相對應的 hooks 處理稍微複雜一點的元件了。

  • useState: 加入元件狀態,但這裡的 setState 不會幫我們自動合併物件型態的狀態,需要用 callback 方式寫並且自行合併
  • useReducer: 可以用來處理物件型態的狀態
  • useEffect: 處理 side effect,取代 componentDidMount, componentDidUpdate, componentWillUnmount
  • useCallback: 當 function 需要在 useEffect 中被使用但又不想加入觸發條件
  • useMemo: 把較高成本計算記起來
  • React.memo: 可以當成 Functional 的 Pure Component
useEffect(() => &#123;
  setState((prevState) => &#123;
    // 用 Object.assign
    return &#123; ...prevState, ...props.updatedValues &#125;;
  &#125;);
&#125;, [props.updatedValues]);

// class-based 中用 callback 設定的
const [state, setState] = useState(() => &#123;
  const initialState = someExpensiveComputation(props);
  return initialState;
&#125;);

const memoizedCallback = useCallback(fn, [...deps]);
useMemo(() => fn, [...deps]);

Functional Component vs Class-based Component

大多數的情境在 Hooks 出現後都可以取代 Class-based 的寫法,優缺點比較:

項目FunctionalClass-based
編譯快勝 (少了 class 轉成 ES5)
更少程式碼勝 (沒有繼承)
測試容易勝 (元件週期單純)
this 的影響勝 (閉包會抓住值)this.props (state) 會改變
複雜狀態操作勝 (有 batch,可同時設多個狀態,自動合併狀態物件)
複雜的情境架構上就要切割乾淨勝 (較多元件週期可以操作)

喜歡這篇文章,請幫忙拍拍手喔 🤣

share