Skip to content

使用 Hooks 的重要规范

再次强调命名规范 useXxx

Hooks 使用规范

  • 只能用于 React 函数组件和自定义 Hook 中,其他地方不可以
  • 只能用于顶层代码,不能在循环,判断中使用 Hooks
  • eslint 插件 eslint-plugin-react-hooks 可以帮到你

错误例子

js
function Demo() {
  const [count, setCount] = useState(0);

  // 错误例子
  if (count) {
    useEffect(() => {
      console.log('count', count);
    });
  }
  // 错误例子
  for (let i = 0; i < 100; i++) {
    const [age, setAge] = useState(0);
  }
  // 错误例子
  if (!count) {
    return;
  }

  //....
}

eslint-plugin-react-hooks 配置

json
// ESLint 配置
{
  "plugins": [
    // ...
    "react-hooks"
  ],
  "rules": {
    // ...
    "react-hooks/rules-of-hooks": "error", // 检查 Hook 的规则
    "react-hooks/exhaustive-deps": "warn" // 检查 effect 的依赖
  }
}

Hooks 的调用顺序

Hooks 调用顺序必须保持一致

  • 无论是 render 还是 re-render,Hooks 调用顺序必须一致
  • 如果 Hooks 出现在循环,判断里,则无法保证顺序一致
  • Hooks 严重依赖于调用顺序!特别重要

例子

js
import React, { useEffect, useState } from 'react';

function TeachDemo({ couseName }) {
  // 函数组件,纯函数,执行完即销毁
  // 所以,无论组件初始化(render)还是组件更新(re-render)
  // 都会重新执行一次这个函数,获取最新的组件
  // 这一点和 class 组件不一样

  // render: 初始化 state 的值 '张三'
  // re-render: 读取 state 的值 '张三'
  const [studentName, setStudentName] = useState('张三');

  // 错误代码================
  // if(couseName){
  // const [studentName, setStudentName] = useState('张三')
  // }
  // 错误代码 end================

  // render: 初始化 state 的值 'lzw'
  // re-render: 读取 state 的值 'lzw'
  const [teacherName, setTeacherName] = useState('lzw');

  // 错误代码================
  // if(couseName){
  //   const [studentName, setStudentName] = useState('张三')
  //   const [teacherName, setTeacherName] = useState('lzw')
  // }

  // if(couseName){
  //   useEffect(() => {
  //     // 模拟学生签到
  //     localStorage.setItem('name', studentName)
  //   })
  // }
  // 错误代码 end================

  // render: 添加 effect 函数
  // re-render: 替换 effect 函数(内部的函数也会重新定义)
  useEffect(() => {
    // 模拟学生签到
    localStorage.setItem('name', studentName);
  });

  // render: 添加 effect 函数
  // re-render: 替换 effect 函数(内部的函数也会重新定义)
  useEffect(() => {
    // 开始上课
    console.log(`${teacherName} 开始上课,学生 ${studentName}`);
  });

  return (
    <div>
      课程:{couseName}, 讲师:{teacherName}, 学生:{studentName}
    </div>
  );
}

export default TeachDemo;

测试代码

js
<TeachDemo couseName={'前端课程'}></TeachDemo>

基于 MIT 许可发布