- Published on
React Component Design - Render Props Component
- Authors
- Name
- Alex Yu
讓我們一樣以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 function
把Toggle
的on
state 跟toggle
傳給children
,由children
自行決定要render
什麼東西,這樣的方式更有彈性可以決定要顯示什麼樣子的 component,也可以明確知道on
跟toggle
是來自於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
的時候會再更詳細說明優缺點。