Render Props 模式
render prop
這個術語指的是一種在 React 元件之間共享程式碼的技巧,其核心是使用一個值為函數的 prop。
擁有 render prop 的元件接受一個「返回 React 元件的函數」,而不是實現自己的渲染邏輯。在渲染時,該元件呼叫這個函數,並使用它返回的 React 元件。
<Title render={() => <h1>I am a render prop!</h1>} />
<DataProvider render={(data) => <h1>Hello {data.target}</h1>} />
白話來說,就是把 render 函式,當成 props 傳遞給另一個元件。
在 <Title />
元件內,我們可以透過返回調用的 render prop 來渲染這些資料!
儘管它們被稱為 render props,但渲染 props 並不一定要被呼叫 render。任何渲染 JSX 的 prop 都被視為渲染 prop!
讓我們重命名上一個範例中使用的 props,並給它指定特定的名稱!
<DataProvider title={(data) => <h1>Hello {data.target}</h1>} />
生活中常見的 Render Props
React Router
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route } from "react-router-dom";
ReactDOM.render(
<Router>
<Route path="/home" render={() => <div>Home</div>} />
<Route
path="/welcome/:username"
render={(routeProps) => <Component {...routeProps} />}
/>
</Router>,
node
);
React Router 的 render 屬性就是一個 render prop 實踐範例,讓你可以用 function 動態決定要渲染什麼內容,並且取得路由相關的所有資訊。
<Route path="/home" render={() => <div>Home</div>} />
這一行的意思是:當網址符合 /home 時,React Router 會呼叫 render 這個 function,然後渲染 <div>Home</div>
。
<Route
path="/welcome/:username"
render={(routeProps) => <Component {...routeProps} />}
/>
這一段則是:當網址符合 /welcome/某個使用者名稱
時,React Router 會呼叫 render 這個 function,並且把目前的路由資訊(像是 match, location, history 等)作為 routeProps 傳進來。
你可以把這些 props 傳給你自己的元件 <Component {...routeProps} />
,這樣你的元件就能取得目前的路由狀態、參數等資訊。
render 屬性本質上就是一個 render prop。 它讓你可以根據路由狀態,動態決定要渲染什麼內容,甚至可以把路由資訊傳遞給子元件。 這種寫法比單純用 component 屬性更靈活,因為你可以在 function 裡做判斷、包裝、甚至條件渲染。
Popover
這段程式碼展示了如何在自訂元件(這裡是 Popover)中使用 render props 的設計模式。
import React from "react";
import { Button, Popover } from "src/components";
const App = () => (
<Popover
content={() => (
<div>
<p>Content</p>
<p>Content</p>
</div>
)}
title="Title"
>
<Button type="primary">Hover me</Button>
</Popover>
);
export default App;
- content 屬性就是 render prop
- 這裡的 content 屬性是一個
function(() => (...))
,這就是 render prop。 - 當 Popover 需要顯示內容時,會呼叫這個 function,然後把回傳的 JSX 當作彈出視窗的內容顯示出來。
- 這種寫法讓 Popover 的內容可以非常彈性,因為你可以根據不同情境傳入不同的 function,甚至可以根據外部狀態動態產生內容。
- 這裡的 content 屬性是一個
- title 屬性
- title 這裡是一般的字串 prop,作為 Popover 的標題。
- children
<Button type="primary">Hover me</Button>
是 Popover 的 children,通常會是觸發 Popover 顯示的元素(例如滑鼠 hover 或點擊時顯示 Popover)。
這種設計讓 Popover 元件的內容(content)可以完全由外部決定,不需要 Popover 自己寫死內容。 只要傳入不同的 function,Popover 就能顯示不同的內容,這就是 render props 的彈性與威力。 這種模式常見於 UI 元件庫(像是 Tooltip、Popover、Modal 等),讓元件更通用、更容易擴充。
結論
- render props 的妙處在於接收 props 的元件是可重用的,可以多次使用它,每次都把不同的值傳遞給 render prop。
- 換個角度來想,傳入的 props,也是能夠被重複使用的。