如何寫一個最簡單的 Render Props?
Render Props 是 React 的一種開發模式,儘管我們都曾接觸過、都會用它(比如在 react-router 的 Route、Context的Consumer),可是我們可能不曾寫過,或是寫過了卻把它當做是一個新東西,這樣子的想法違背了 React 的核心思想。
4 min readFeb 16, 2019
首先,我自己常看到的 Render Props 通常是這兩種形式。
- 透過名為
render
的屬性傳遞,並且生出一個變數導入子組件並渲染,此變數是由<Something>
組件賦予的,這裡以history
為例子:
<Route path="/" render={
({history})=> <Child prop={prop} history={history}>
}
/>
- 透過直接嵌套在裡頭(本質上是透過
children
傳遞),Context API 就是以此方式做透過 Consumer 傳遞。
<Consumer>
{value=> <Child val={value}>}
</Consumer>
Render Props 在幹嘛?
也就是說,只要知道這張圖,大致上可以知道我們其實把「渲染子組件」這件事拆分成「先有一個函數」、並且「透過它渲染不一樣的子組件」
那麼Render Props裡頭在做什麼呢?
我們從這圖知道幾件事
- 這個
newChild
,接受一個 Function 作為參數,而且這個Function可以生成(渲染)出Child
組件。 - new Child 必須提供傳入 Function(
val=><Child prop={val}/>
)的參數val
。 - 這個函數會從兩個地方進來,
props.render
或是props.children
。
知道這些後,我們就能自己來寫一個簡單的 Render Props 了!
你組件.jsx
import Something from './Something';
<div>
<Something> { val=><Test text={val} />} </Something>
<div>
Test.jsx
export default ({text})=>(
<div>
<h1>Here is Test Component </h1>
<p> Text from Props {text} </p>
</div>)
Something.jsx
export default ({children})=>{
// children 會是一個function
// 就是 val => <Test text={val}/>
// 也就是我們怎麼“呼叫”這個函數,間接的決定Test的text props return children('From something');
// 會把 children 渲染出來回傳
}
如果覺得看灰底黑字看到快眼脫的,就看看 codesandbox 吧!
所以 Render Props 不是新東西嗎?
不是,絕對不是,如果你沒有跳脫組件的思維,那麼你沒有辦法很徹底的了解 React,以及使用 JSX 的意義。
每一個組件可以接受 Props,且可以 Render 出其他組件,這句話聽起來不是挺耳熟的嗎?
JavaScript 中的函數可以接受參數,參數可以是函數(高階函數的用法),也可以 Return 函數出來(科里化的用法)。
components.jsx
({children})=> children(123)
// return <Child test={123}>
甚至是用 stateful 的類組件把原始 Child 組件給 wrapped 起來,也是如此。
跟在撰寫原生 JavaScript 時,透過 Proxy ,或類似技術(比如Override),把原本要執行的函數給「加料」罷了。