Hook 规则 – React

Souleigh ✨ 等级 703 0 0
标签: reacthttps前端

Hook 规则

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

Hook 本质就是 JavaScript 函数,但是在使用它时需要遵循两条规则。我们提供了一个 linter 插件来强制执行这些规则:

只在最顶层使用 Hook

不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层调用他们。遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用。这让 React 能够在多次的 useStateuseEffect 调用之间保持 hook 状态的正确。(如果你对此感到好奇,我们在下面会有更深入的解释。)

只在 React 函数中调用 Hook

不要在普通的 JavaScript 函数中调用 Hook。你可以:

  • ✅ 在 React 的函数组件中调用 Hook
  • ✅ 在自定义 Hook 中调用其他 Hook (我们将会在下一页 中学习这个。)

遵循此规则,确保组件的状态逻辑在代码中清晰可见。

ESLint 插件

我们发布了一个名为 eslint-plugin-react-hooks 的 ESLint 插件来强制执行这两条规则。如果你想尝试一下,可以将此插件添加到你的项目中:

我们打算后续版本默认添加此插件到 Create React App 及其他类似的工具包中。

npm install eslint-plugin-react-hooks --save-dev
// 你的 ESLint 配置
{
  "plugins": [
    // ...
    "react-hooks"
  ],
  "rules": {
    // ...
    "react-hooks/rules-of-hooks": "error", // 检查 Hook 的规则
    "react-hooks/exhaustive-deps": "warn" // 检查 effect 的依赖
  }
}

现在你可以跳转到下一章节学习如何编写你自己的 Hook在本章节中,我们将继续解释这些规则背后的原因。

说明

正如我们之前学到的,我们可以在单个组件中使用多个 State Hook 或 Effect Hook

function Form() {
  // 1. Use the name state variable
  const [name, setName] = useState('Mary');

  // 2. Use an effect for persisting the form
  useEffect(function persistForm() {
    localStorage.setItem('formData', name);
  });

  // 3. Use the surname state variable
  const [surname, setSurname] = useState('Poppins');

  // 4. Use an effect for updating the title
  useEffect(function updateTitle() {
    document.title = name + ' ' + surname;
  });

  // ...
}

那么 React 怎么知道哪个 state 对应哪个 useState?答案是 React 靠的是 Hook 调用的顺序。因为我们的示例中,Hook 的调用顺序在每次渲染中都是相同的,所以它能够正常工作:

// ------------
// 首次渲染
// ------------
useState('Mary')           // 1. 使用 'Mary' 初始化变量名为 name 的 state
useEffect(persistForm)     // 2. 添加 effect 以保存 form 操作
useState('Poppins')        // 3. 使用 'Poppins' 初始化变量名为 surname 的 state
useEffect(updateTitle)     // 4. 添加 effect 以更新标题

// -------------
// 二次渲染
// -------------
useState('Mary')           // 1. 读取变量名为 name 的 state(参数被忽略)
useEffect(persistForm)     // 2. 替换保存 form 的 effect
useState('Poppins')        // 3. 读取变量名为 surname 的 state(参数被忽略)
useEffect(updateTitle)     // 4. 替换更新标题的 effect

// ...

只要 Hook 的调用顺序在多次渲染之间保持一致,React 就能正确地将内部 state 和对应的 Hook 进行关联。但如果我们将一个 Hook (例如 persistForm effect) 调用放到一个条件语句中会发生什么呢?

 // 🔴 在条件语句中使用 Hook 违反第一条规则
  if (name !== '') {
    useEffect(function persistForm() {
      localStorage.setItem('formData', name);
    });
  }

在第一次渲染中 name !== '' 这个条件值为 true,所以我们会执行这个 Hook。但是下一次渲染时我们可能清空了表单,表达式值变为 false。此时的渲染会跳过该 Hook,Hook 的调用顺序发生了改变:

useState('Mary')           // 1. 读取变量名为 name 的 state(参数被忽略)
// useEffect(persistForm)  // 🔴 此 Hook 被忽略!
useState('Poppins')        // 🔴 2 (之前为 3)。读取变量名为 surname 的 state 失败
useEffect(updateTitle)     // 🔴 3 (之前为 4)。替换更新标题的 effect 失败

React 不知道第二个 useState 的 Hook 应该返回什么。React 会以为在该组件中第二个 Hook 的调用像上次的渲染一样,对应的是 persistForm 的 effect,但并非如此。从这里开始,后面的 Hook 调用都被提前执行,导致 bug 的产生。

这就是为什么 Hook 需要在我们组件的最顶层调用。 如果我们想要有条件地执行一个 effect,可以将判断放到 Hook 的_内部_:

 useEffect(function persistForm() {
    // 👍 将条件判断放置在 effect 中
    if (name !== '') {
      localStorage.setItem('formData', name);
    }
  });

注意:如果使用了提供的 lint 插件,就无需担心此问题。 不过你现在知道了为什么 Hook 会这样工作,也知道了这个规则是为了避免什么问题。

收藏
评论区

相关推荐

React Hooks 快速上手
React Hook 快速上手 一、 Hook 简介 1.1 Hook历史 在React Hook出现之前的版本中,组件主要分为两种:函数式组件和类组件。其中,函数式组件通常只考虑负责UI的渲染,没有自身的状态也没有业务逻辑代码,是一个纯函数。而类组件则不同,类组件有自己的内部
10分钟教你手写8个常用的自定义hooks
前言 Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。本文是一篇以实战为主的文章,主要讲解实际项目中如何使用hooks以及一些最佳实践,不会一步步再介绍一遍react hooks的由来和基本使用,因为写hooks的文章很多,而且官网对于react hooks的介绍也很详细
Hook 简介 – React
Hook 简介 _Hook_ 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。 import React, { useState } from 'react'; function Example() { // 声明一个新的叫做 “count” 的 sta
Hook 规则 – React
Hook 规则 _Hook_ 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。 Hook 本质就是 JavaScript 函数,但是在使用它时需要遵循两条规则。我们提供了一个 linter 插件(https://www.npmjs.com/package/
Hook 概览 – React
Hook 概览_Hook_ 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。Hook 是。本页面为有经验的 React 用户提供一个对 Hook 的概览。这是一个相当快速的概览,如果你有疑惑,可以参阅下面这样的黄色提示框。 详细说明 有关我们为什么要在 Rea
使用 State Hook – React
使用 State Hook_Hook_ 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。中使用下面的例子介绍了 Hook:import React, { useState } from 'react';function Example() { //
使用 Effect Hook – React
使用 Effect Hook_Hook_ 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。_Effect Hook_ 可以让你在函数组件中执行副作用操作import React, { useState, useEffect } from 'reac
Hook 规则 – React
Hook 规则_Hook_ 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。Hook 本质就是 JavaScript 函数,但是在使用它时需要遵循两条规则。我们提供了一个 来强制执行这些规则: 只在最顶层使用 Hook不要在循环,条件或嵌套函数中调用 Hoo
自定义 Hook – React
自定义 Hook_Hook_ 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。通过自定义 Hook,可以将组件逻辑提取到可重用的函数中。在我们学习 时,我们已经见过这个聊天程序中的组件,该组件用于显示好友的在线状态:import React, { useSta
Hook API 索引 – React
Hook API 索引_Hook_ 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。本页面主要描述 React 中内置的 Hook API。如果你刚开始接触 Hook,那么可能需要先查阅 。你也可以在 章节中获取有用的信息。 基础 Hook
React Hook丨用好这9个钩子,所向披靡
React Hook 指南 什么是 Hook ? Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。 Hook 本质上就是一个函数,它简洁了组件,有自己的状态管理,生命周期管理,状态共享。 useState useEffect useContext us
10分钟教你手写8个常用的自定义hooks
https://juejin.im/post/5e57d0dfe51d4526ce6147f2 前言 -- Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。本文是一篇**以实战为主的文章,主要讲解实际项目中如何使用hooks以及一些最佳实践**,不会一步步再介
React Hook
用React Hook写一个简单的登录表单示例,两种方式: 第一种: import React, { useState } from "react"; import ReactDOM from "react-dom"; function LoginForm() { const [username, setUsern
React Hooks 完整学习笔记
https://juejin.im/post/5e687c26e51d45272443f7d8 时长:预计 30 min 面向:React Hook 初学者 版本:React 16.13.0 + TypeScript 3.7.2 原文:[获得更好阅读体验](https://www.oschina.net/action/GoToLink?url
React 新特性 React Hooks 的使用
关注 前端技术专栏 ,回复“ 资源 ”免费领取全套视频教程 **正文** ### **什么是Hooks?** Hooks是React 16.8的新增特性。 它可以让你在不编写class的情况下使用state以及其他的React特性。 是一些可以让你在函数组件里“钩入” React state及生命周期等特性的函数。 Ho