使用 render props 抽象 Modal 組件的狀態

使用 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> ); }}

是不是乾淨很多 ??。

完整的例子可以查看 codesandbox.io/s/85pq1r

當然我們還可以把這個模式應用到其他類似 Modal 這樣的組件上,我們可以封裝一個叫 Toggle 的組件來控制 PopoverTooltip

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 終極配置

TAG:React | 前端開發 |