Skip to content
On this page

用 Hooks 的思想开发前端

前言

在 React Hooks 发布以来,大家对 Hooks 的接受程度差别很多。

对于一个习惯了 Hooks 的前端开发来说,真的不明白为什么还有人不去尝试 Hooks?

可能是还没真正感受到 Hooks 的强大之处。因为 Hooks 一开始发布的时候,我就去尝试过这个新 API,但是对于官网的 DEMO 和编写的 DEMO 来说,并未体会到和 Component 多大的差别。

Hooks 和 Component 的差别

很多人可能和我刚开始一样,不明白为什么 Hooks 这么深受欢迎,它和 Component 的差别在哪里。

其实它们之间最大的差别在于,Component 是对于组件的抽取,而 Hooks 是对于 逻辑 的抽取。他其实可以理解为一个响应式的公用的函数。

从弹窗开关讲 Hooks

前端对于模态框肯定不会陌生,一个网站或多或少都有几个模态框,对于模态框组件我们简单实现一个:

javascript
import * as React from 'react'
import { createPortal } from 'react-dom'
export interface IModalProps {
  visible: boolean
  onClose: () => void
  children: React.ReactNode
}
const Modal: React.FC<IModalProps> = props => {
    // 根据 props.visible 处理显示隐藏等逻辑
    // ...
  return createPortal((
    <div className='modal'>
      {props.children}
    </div>
  ), document.body)
}
export default Modal

那么父组件使用这个弹窗的时候,就需要点击打开弹窗,点击“关闭”时关闭弹窗

Component 使用方式

javascript
import * as React from 'react'
import Modal from './Modal'
interface IDemoState {
  visible: boolean
}
class Demo extends React.Component<any, IDemoState> {
  constructor(props: any) {
    super(props)
    this.state = {
      visible: false,
    }
  }
  public render() {
    return (
      <>
        <button onClick={this.open}>
          open modal
        </button>
        <Modal
          visible={this.state.visible}
          onClose={this.close}>
          children
        </Modal>
      </>
    )
  }
  private open = () => {
    this.setState({
      visible: true,
    })
  }
  private close = () => {
    this.setState({
      visible: false,
    })
  }
}

Function Component 方式

在函数组件中使用 useState 代替 React Component 中的 State

javascript
import * as React from 'react'
import Modal from './Modal'
const Demo: React.FC = () => {
  const [visible, setVisible] = React.useState(false)
  const open = React.useCallback(() => {
    setVisible(true)
  }, [])
  const close = React.useCallback(() => {
    setVisible(false)
  }, [])
  return (
    <>
      <button onClick={open}>
        open modal
      </button>
      <Modal
        visible={visible}
        onClose={close}>
        children
      </Modal>
    </>
  )
}

useState 代替了 Component 中的 State,在代码量上已经减少了很多,但是在实际开发中,可能会有中模态框,那么就有大量的 visibleopenclose 这种模态框控制变量。

使用 Hooks 的方式

在大量定义 visibleopenclose 这种重复的变量,重复的逻辑,在以前 Component 的开发方式中,很难将这些复用,就会使用 HOC 等方式解决

好在 Hooks 出现了,我们将这部分抽取成一个 useTrigger 的 Hook 函数

javascript
export function useTrigger(initialValue = false) {
  const [visible, setVisible] = React.useState(initialValue)
  const open = React.useCallback(() => {
    setVisible(true)
  }, [setVisible])
  const close = React.useCallback(() => {
    setVisible(false)
  }, [setVisible])
  return {
    visible,
    open,
    close,
  }
}

这样子的话我们修改一下上面对 Modal 的用法

javascript
const Demo: React.FC = () => {
  const trigger = useTrigger()
  return (
    <>
      <button onClick={trigger.open}>
        open modal
      </button>
      <Modal
        visible={trigger.visible}
        onClose={trigger.close}>
        children
      </Modal>
    </>
  )
}

没错,这就是 Hooks,在用到 Modal 的地方一个 const trigger = useTrigger()就解决了大量的重复工作。

其他 Hooks

在 React 开发过程中,其实还有很多类似的地方,一直做着重复的工作占用了我们大量的时间,比如在使用输入框时定义了一次又一次的 valuehandleChange,同样都可以用 Hooks 的方式解决

javascript
export function useInputChange(defaultValue = '') {
  const [value, setValue] = useState(defaultValue)
  const handleChange = useCallback((evt: React.ChangeEvent) => {
    const { value } = evt.target as HTMLInputElement
    setValue(value)
  }, [])
  return {
    value,
    handleChange,
  }
}

还有在页面装载完成后去请求数据等

javascript
import { useState, useEffect } from 'react'
export function useFetch(opts) {
  const [loading, setLoading] = useState(true)
  const [data, setData] = useState(null)
  const loadData = async () => {
    // ... 加载数据等逻辑
  }
  useEffect(() => {
    loadData()
  }, [])
  return {
    loading,
    data,
    loadData,
  }
}
const Demo = () => {
    const { data, loading } = useFetch('https://api.com')
    return (
        // ... render data
    )
}

没有什么是一个 Hook 解决不了的,如果有,就两个!

在 Vue 中同样类似,以前 Vue 发布过一个 vue-functional-api ,其实就是 Vue 版 的 React Hooks,现在已经变成了 composition-api