使用 render props 抽象 Modal 組件的狀態
來自專欄 Pragmatic React
Modal
是一個使用率很高的組件,然而正是因為其頻繁的使用率,控制它的狀態就變成了一件煩人的事。無論你是把它的 visible
狀態存在組件內部,還是某個狀態管理庫的 "store" 里,你每使用一次 Modal
就要為這個 Modal
新增一個狀態。雖然有類似 redux-modal 這樣的庫來幫你自動管理 Modal
的狀態,但是我發現使用 render props 來抽象出 Modal
的狀態實現起來更簡潔優雅,而且可以不依賴任何的狀態管理庫。
假設有下面這樣一個帶 Modal
的頁面:
import React from react;import { Button, Modal } from "antd";const HelloModal = ({ visible, handleHide }) => ( <Modal visible={visible} title="Hello" onOk={handleHide} onCancel={handleHide}> World! </Modal>);class App extends React.Component { state = { visible: false }; handleShow = () => { this.setState({ visible: true }); }; handleHide = () => { this.setState({ visible: false }); }; render() { const { visible } = this.state; return ( <div> <HelloModal visible={visible} handleHide={this.handleHide} /> <Button type="primary" onClick={this.handleShow}> Click me! </Button> </div> ); }}
我們來把 Modal
的狀態抽取到一個叫 ModalContainer
的組件里:
import React from "react";export default class ModalContainer extends React.Component { state = { visible: false }; show = () => { this.setState({ visible: true }); }; hide = () => { this.setState({ visible: false }); }; render() { const { visible } = this.state; const { children } = this.props; return children({ visible: visible, show: this.show, hide: this.hide }); }}
然後我們就可以在上面的頁面中這樣用這個 ModalContainer
:
class App extends React.Component { render () { return ( <ModalContainer> {modal => ( <div> <HelloModal visible={modal.visible} handleHide={modal.hide} /> <Button type="primary" onClick={modal.show}> Click me! </Button> </div> )} </ModalContainer> ); }}
是不是乾淨很多 ??。
完整的例子可以查看 https://codesandbox.io/s/85pq1rmjl
當然我們還可以把這個模式應用到其他類似 Modal
這樣的組件上,我們可以封裝一個叫 Toggle
的組件來控制 Popover
和 Tooltip
:
import { Button, Popover } from antd;class Toggle extends React.Component { state = { on: this.props.initial, }; toggle = () => { this.setState(({ on }) => ({ on: !on, })); }; render() { return this.props.children({ on: this.state.on, toggle: this.toggle }); }}ReactDOM.render( <Toggle> {popover => ( <div> <Popover placement="bottom" visible={popover.on} content="world!" title="Hello" > <Button type="primary" onClick={popover.toggle}> Button </Button> </Popover> </div> )} </Toggle>, mountNode,);
最後推薦一個來之評論區的庫:renatorib/react-powerplug
推薦閱讀:
※React首次渲染
※一條命令創建免配置的 React + Antd + Typescript 項目
※巧用React Fiber中的渲染字元串新功能
※Build Your Own React:第一次渲染
※JS/React 開發者的 Atom 終極配置