阅读 700

一个hooks的“奇异”用法

React hooks最激动人心的部分无疑是自定义hook,充满了无限的可能和可复用性,同时让代码前所未有得清晰。

  • 如何现在就使用hooks?
# 创建项目
create-react-app myApp
# 进入项目目录
cd myApp
# 升级 react 和 react-dom
yarn add react@next react-dom@next
复制代码

即可。

今天写了一个奇异的custom hooks,奇异之处在于返回了组件。

一个普通的 antdModal 用例如下:
官网链接

import { Modal, Button } from 'antd';

class App extends React.Component {
  state = { visible: false }

  showModal = () => {
    this.setState({
      visible: true,
    });
  }

  handleOk = (e) => {
    console.log(e);
    this.setState({
      visible: false,
    });
  }

  handleCancel = (e) => {
    console.log(e);
    this.setState({
      visible: false,
    });
  }

  render() {
    return (
      <div>
        <Button type="primary" onClick={this.showModal}>
          Open Modal
        </Button>
        <Modal
          title="Basic Modal"
          visible={this.state.visible}
          onOk={this.handleOk}
          onCancel={this.handleCancel}
        >
          <p>Some contents...</p>
          <p>Some contents...</p>
          <p>Some contents...</p>
        </Modal>
      </div>
    );
  }
}

ReactDOM.render(<App />, mountNode);
复制代码

会不会觉得好烦? 我就想用一下弹层,怎么又要定义 visible 的 state,又要写 showModal 方法。

<Button type="primary" onClick={this.showModal}>
  Open Modal
</Button>
<Modal
  title="Basic Modal"
  visible={this.state.visible}
  onOk={this.handleOk}
  onCancel={this.handleCancel}
>
  <p>Some contents...</p>
  <p>Some contents...</p>
  <p>Some contents...</p>
</Modal>
复制代码

能否简化成

<Button type="primary">
  Open Modal
</Button>
<Modal
  title="Basic Modal"
  onOk={this.handleOk}
>
  <p>Some contents...</p>
  <p>Some contents...</p>
  <p>Some contents...</p>
</Modal>
复制代码

呢?可以。

于是我写了这个demo:Code Demo

const App = () => {
  const {MyBtn, MyModal} = useModal()
  return (
    <div>
      <MyBtn type="primary">Click me!</MyBtn>
      <MyModal title="Basic Modal" onOK={() => alert('everything is OK')}>
        <p>Some contents...</p>
        <p>Some contents...</p>
        <p>Some contents...</p>
      </MyModal>
    </div>
  )
}
复制代码

这里的 useModal 是一个 custom hooks。实现代码是

import React, {useState} from 'react'
import 'antd/dist/antd.css'
import {Button, Modal} from 'antd'

const useModal = () => {
  const [on, setOn] = useState(false)
  const toggle = () => setOn(!on)
  const MyBtn = props => <Button {...props} onClick={toggle} />
  const MyModal = ({onOK, ...rest}) => (
    <Modal
      {...rest}
      visible={on}
      onOk={() => {
        onOK && onOK()
        toggle()
      }}
      onCancel={toggle}
    />
  )
  return {
    on,
    toggle,
    MyBtn,
    MyModal,
  }
}
复制代码

对于使用者甚至不用关心具体实现,直接把 Button 和 Modal 拿来用就好,点击 Button 就会弹 Modal,什么 visible,toggle,onClick 等只和 Modal 内部实现相关的逻辑全全隐藏了。

大家怎么看?

补充:一直觉得这么写有点性能问题,在reddit上问了下,Dan 给出的回复如下:

The problem with this code is that it returns a new component type on every render. This means that the >state of all components below Modal will be reset because OldModal !== NewModal on every next render. >You can learn more about it here: reactjs.org/docs/reconc…

Instead, you can return elements directly. But don't return components.

简单的说,返回 Modal 组件,由于React内部diff的判定方式,会认为任何两次渲染中 type 都不同,所以会使得 Modal 的所有子树每次都丢弃并重新渲染。这不得不说是一个性能问题。所以暂时不推荐用此 hook。

关注下面的标签,发现更多相似文章
评论