續前篇提出的疑問 Modal in React ( React 當中的互動視窗、對畫框) : 如何從外部帶入元件?
Show me the code: Codesandbox Demo
以下範例
function BootstrapModalExample() {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
return (
<>
<Button variant="primary" onClick={handleShow}>
Launch demo modal
</Button>
{/* Modal */}
<Modal show={show} onHide={handleClose}>
{/* 裡面是Modal元件內其他東西,這邊先忽略 */}
</Modal>
</>
);
}
<BootstrapModalExample
component={<Button variant="primary">Launch demo modal</Button>}
/>
function BootstrapModalExample({ component }) {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
return (
<>
{component}
{/* <Button variant="primary" onClick={handleShow}>
Launch demo modal
</Button> */}
{/* Modal */}
<Modal show={show} onHide={handleClose}>
{/* 裡面是Modal元件內其他東西,這邊先忽略 */}
</Modal>
</>
);
}
發現我們沒辦法將 handleShow
(onClick handler) 這個 callback 放進去。
這時我們遇到一個問題,我們該如何把 子元件 的狀態 丟給 父元件 使用?
這代表我們想要將 Children 進行一段加工,然後在渲染,這時我們想到可以使用 render props 的技巧。定義一個 function 作為 props 。 並在這 function 當中把 handleShow
作為input,然後output出展示元件,且在該元件帶入 handleShow
。
<>
{renderTrigger && renderTrigger( handleShow )}
{/* component */}
{/* <Button variant="primary" onClick={handleShow}>
Launch demo modal
</Button> */}
{/* Modal */}
<Modal show={show} onHide={handleClose}>
{/* 裡面是Modal元件內其他東西,這邊先忽略 */}
</Modal>
</>
如此我們便能在父層使用
<BootstrapModalExample
renderTrigger={(handleShow) => (
<Button variant="primary" onClick={handleShow}>
Launch demo modal
</Button>
)}
/>
<BootstrapModalExample
renderTrigger={(handleShow) => (
<img onClick={handleShow} src={`https://loremflickr.com/200/200`} />
)}
/>
為避免我們 呼叫 <BootstrapModalExample/>
這個元件時,忘記帶入 props 導致我們的 App Crash,我們可在 renderTrigger( handleShow )
之前加入一組短路: renderTrigger && renderTrigger( handleShow )
。 使我們就算忘記帶入props 不至於導致 App crash ( 只不過此時也什麼都不會出現XDD )
<>
{renderTrigger && renderTrigger( handleShow )}
{/* Modal */}
<Modal show={show} onHide={handleClose}>
{/* 裡面是Modal元件內其他東西,這邊先忽略 */}
</Modal>
</>
使我們的 render props 更彈性,假如我們不只想要帶入 handleShow
,還想帶入更多東西的話。
我們將 renderTrigger 這個 function 改吃 一個物件,這樣執行 function 時,需要帶入的 input 成為一個物件,在這個物件當中,我們就可以放入其他需要的東西了。
<>
{renderTrigger && renderTrigger( { handleShow, loading, someOtherYouNeed } )}
{/* Modal */}
<Modal show={show} onHide={handleClose}>
{/* 裡面是Modal元件內其他東西,這邊先忽略 */}
</Modal>
</>
React 官網 render props
如何寫一個最簡單的 Render Props?
HOC 與Render Props,談我從她們身上學到什麼