教程:FullStackOpen2022 / Part 7 / 自定义 hooks

本文以 routed-anecdotes 应用为例。对应练习 7.4-7.6。

1. React Hooks

React 提供了多种不同的 Hooks,其中最常用的是 useStateuseEffect,又比如 useImperativeHandle,它允许组件向其他组件提供其功能。

Hook 不是普通的函数,在使用这些 Hooks 时,必须遵守某些规则或限制:

  • 不要在循环、条件或嵌套函数中调用 Hooks。即,总是在 React 函数的顶层使用 Hooks。
  • 不要从普通的 JavaScript 函数中调用 Hooks。即,可以从 React 函数组件调用,或从自定义 Hooks 中调用 Hooks。

有现有的 ESlint 规则 eslint-plugin-react-hooks 可以用来验证应用是否正确使用 Hooks。

更多信息可见:useHooks

2. Custom Hooks

React 提供了创建自定义的 Custom Hooks 的选项。

Custom Hooks 的主要目的是促进组件中使用的逻辑的重用,可以使用任何其他 Hooks。Custom Hooks 需要遵守 React Hooks 的规则,此外,名称必须以 use 这个词开头。

表单的每个字段都有自己的状态。为了使表单的状态与用户提供的数据保持同步,必须为每个输入元素注册一个适当的onChange处理程序。下面让试着自定义 useField Hook 来简化表单的状态管理。

hooks/index.js:

import { useState } from 'react'

export const useField = (type) => {
  const [value, setValue] = useState('')

  const onChange = (event) => {
    setValue(event.target.value)
  }

  const reset = () => {
    setValue('')
  }

  return {
    reset,
    type,
    value,
    onChange,
  }
}

该 Hook 接收输入字段的类型作为参数,返回输入所需的所有属性:其类型、值和 resetonChange 处理程序。

这个 Hook 可以用以下方式使用:

const CreateNew = (props) => {
  const { reset: content_reset, ...content } = useField('text')

  const handleSubmit = (e) => {
    e.preventDefault()
    props.addNew({
      content: content.value,
    })
  }

  const handleReset = (e) => {
    e.preventDefault()
    content_reset()
  }

  return (
    <div>
      <h2>create a new anecdote</h2>
      <form onSubmit={handleSubmit}>
        <div>
          content
          <input {...content} />
        </div>
        <button type="submit">create</button>
        <button type="button" onClick={handleReset}>
          reset
        </button>
      </form>
    </div>
  )
}

关于代码中使用的 Spread Attributes,更多可见: