react自定义Hook 写法、规则(只能在组件/自定义Hook内调用)

React 自定义 Hook(Custom Hook)本质上是:把组件中可复用的状态逻辑抽出来 。你做过 React,应该见过 useStateuseEffect,自定义 Hook 就是在这些基础上封装逻辑。


1. 自定义 Hook 写法

命名必须以 use 开头:

javascript 复制代码
import { useState } from 'react'

function useCount(initialValue = 0) {
  const [count, setCount] = useState(initialValue)

  const increment = () => {
    setCount(count + 1)
  }

  const decrement = () => {
    setCount(count - 1)
  }

  return {
    count,
    increment,
    decrement
  }
}

export default useCount

使用:

javascript 复制代码
import useCount from './hooks/useCount'

function App() {
  const { count, increment } = useCount(10)

  return (
    <>
      <div>{count}</div>

      <button onClick={increment}>
        +
      </button>
    </>
  )
}

结果:

复制代码
点击按钮
↓
count变化
↓
组件重新渲染

类似把业务逻辑抽出去。


2. React Hook 两条核心规则(必须记)

官方规则可概括成:

规则1:只能在 React 函数组件里调用

✅ 正确:

javascript 复制代码
function User() {
    const [name] = useState('Tom')

    return <div>{name}</div>
}

❌ 错误:

普通函数:

scss 复制代码
function getData() {
    const [name] = useState('Tom')
}

报错:

r 复制代码
Invalid hook call

规则2:只能在自定义 Hook 中调用 Hook

✅ 正确:

csharp 复制代码
function useUser() {
    const [user] = useState(null)

    return user
}

因为:

bash 复制代码
自定义Hook
↓
内部可以继续调用 useState/useEffect

总结成一句:

Hook 只能在:

  • React 函数组件
  • 自定义 Hook(useXXX)

里面调用。


3. Hook 不能写在条件里

这是很多人踩坑。

错误:

javascript 复制代码
function Demo({ show }) {

    if (show) {
        const [count] = useState(0)
    }

    return <div>demo</div>
}

原因:

React 要保证:

makefile 复制代码
第一次渲染:
useState
useEffect

第二次渲染:
useState
useEffect

调用顺序必须一致。

条件会变成:

makefile 复制代码
第一次:
useState

第二次:
无

React 不知道状态对应谁。


正确:

javascript 复制代码
function Demo({ show }) {

    const [count] = useState(0)

    if (show) {
        console.log(count)
    }

    return <div></div>
}

4. Hook 不能写循环

错误:

scss 复制代码
for(let i=0;i<5;i++){
    useState()
}

错误:

scss 复制代码
list.map(() => {
   useEffect()
})

都会破坏调用顺序。


5. Hook 不能写嵌套函数

错误:

scss 复制代码
function App() {

   function handleClick() {
       useState()
   }

}

因为点击时才执行。


6. 自定义 Hook 常见封装

封装请求

以前组件:

scss 复制代码
useEffect(()=>{
   fetchUser()
},[])

抽:

scss 复制代码
function useUser() {
    const [user,setUser] = useState(null)

    useEffect(()=>{
        api.getUser()
          .then(res=>setUser(res))
    },[])

    return user
}

组件:

javascript 复制代码
function App() {
    const user = useUser()

    return <div>{user?.name}</div>
}

类似 Vue Composition API:

scss 复制代码
useUser()

封装窗口监听

javascript 复制代码
function useWindowSize() {

    const [size,setSize] =
        useState(window.innerWidth)

    useEffect(()=>{

        const resize = ()=>{
            setSize(window.innerWidth)
        }

        window.addEventListener(
            'resize',
            resize
        )

        return ()=>{
            window.removeEventListener(
                'resize',
                resize
            )
        }

    },[])

    return size
}

使用:

scss 复制代码
const width = useWindowSize()

7. React 为什么限制 Hook 只能顶层调用?

因为 React 内部靠调用顺序保存状态:

第一次:

scss 复制代码
1 -> useState(count)
2 -> useEffect()
3 -> useState(name)

第二次必须还是:

scss 复制代码
1 -> useState(count)
2 -> useEffect()
3 -> useState(name)

顺序变了:

复制代码
count
name
effect

状态就乱了。

所以才有:

复制代码
不能条件调用
不能循环调用
不能嵌套调用

8. 面试常问总结(建议背)

什么是自定义 Hook?

把组件内可复用的状态逻辑抽离成函数,以 use 开头,可复用 state、副作用、事件等逻辑。

Hook 使用规则?

  1. 只能在函数组件调用
  2. 只能在自定义 Hook 调用
  3. 不能写条件
  4. 不能写循环
  5. 不能写嵌套函数
  6. 必须顶层调用

为什么?

React 依赖 Hook 调用顺序保存状态,顺序变化会导致状态错乱。

这类问题在 React 中高级岗位很常见。

相关推荐
风骏时光牛马6 小时前
C语言核心高频问题与代码实战梳理
前端
葬送的代码人生6 小时前
别再「Ctrl+C/V」了!Git 开发必备技能,10 分钟告别单机码农
前端·github·代码规范
xuankuxiaoyao6 小时前
vue.js 设计与开发 ---路由
前端·javascript·vue.js
ZC跨境爬虫6 小时前
跟着 MDN 学CSS day_6:(伪类和伪元素详解)
前端·javascript·css·数据库·ui·html
idcu6 小时前
Lyt.js + Vite 快速开发指南
前端·typescript
暗不需求6 小时前
玩转 React Hooks:从基础到实战,逐行解析带你彻底掌握
前端·react.js·面试
一颗小青松6 小时前
css 文字区域根据图片形状显示,根据文字设置背景图
前端·css
阿黎梨梨6 小时前
跟 Git 打交道的正确姿势
前端
idcu6 小时前
深入 Lyt.js 路由系统:L6 生态系统层的核心
前端·typescript