Published on

React Component Design - Render Props Component

Authors
  • avatar
    Name
    Alex Yu
    Twitter

讓我們一樣以Toggle作為例子,但這次使用Toggle的方式要類似於下面

function Usage({ onToggle = (...args) => console.log('onToggle', ...args) }) {
  return (
    <Toggle onToggle={onToggle}>
      {({ on, toggle }) => (
        <div>
          {on ? 'The button is on' : 'The button is off'}
          <Switch on={on} onClick={toggle} />
          <hr />
          <button aria-label="custom-button" onClick={toggle}>
            {on ? 'on' : 'off'}
          </button>
        </div>
      )}
    </Toggle>
  );
}

要符合這樣的使用方式其實不難,程式碼如下

import React from 'react';
import { Switch } from '../switch';

class Toggle extends React.Component {
  state = { on: false };
  toggle = () =>
    this.setState(
      ({ on }) => ({ on: !on }),
      () => this.props.onToggle(this.state.on)
    );
  getStateAndHelpers() {
    return {
      on: this.state.on,
      toggle: this.toggle,
    };
  }
  render() {
    return this.props.children(this.getStateAndHelpers());
  }
}

可以看到render functionToggleon state 跟toggle傳給children,由children自行決定要render什麼東西,這樣的方式更有彈性可以決定要顯示什麼樣子的 component,也可以明確知道ontoggle是來自於Toggle。跟Compound component的設計方式比起來,個人覺得這樣的方式有幾個優點:

  • 少了複雜的 Provider/Context state 傳遞關係
  • 不用 validate children 是不是有在Toggle的定義介面裡

但缺點也很明顯,雖然這樣的設計方式保持最大的彈性讓 children 自行決定要 render 什麼樣的東西,但這既是優點也是缺點,因為這樣的 component 所持有的邏輯過少,children 還是需要自行決定顯示的內容。另外一個缺點則是如果 component 都採用這樣的方式,則會讓 component 的層級過於多層,底層的 children component 最終會很難排查 props 是從何而來。

雖然還沒介紹到HOC component的設計方式,但這邊引述一下react-router的作者 Michael Jackson 提到這樣做比HOC component好的原因還有:

  • 解決了 naming collision 的問題
  • HOC component比起來提供更多的彈性可以決定render什麼樣的東西,換句話說,這樣的方式直接可以取代HOC component,但是,HOC component卻沒辦法取代Render props

之後等介紹到HOC component的時候會再更詳細說明優缺點。