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

React 自定义 Hook(Custom Hook)本质上是:把组件中可复用的状态逻辑抽出来 。你做过 React,应该见过 useState、useEffect,自定义 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 中高级岗位很常见。

相关推荐
IMPYLH1 分钟前
HTML 的 <th> 元素
前端·html
风骏时光牛马2 分钟前
AI浪潮下程序员的职场破局与能力成长思考
前端
IMPYLH8 分钟前
HTML 的 <thead> 元素
前端·html
FungLeo9 小时前
成为全栈·React 管理后台篇·总复盘:从“接口能调通”到“后台值得使用”
前端·react.js·前端框架·项目复盘·成为全栈
Csvn10 小时前
并发模式:让渲染学会排队、插队和让路
前端
可乐鸡翅yeah_10 小时前
新手梳理:M3U8 线上问题,哪些是前端锅,哪些是后端锅
前端·ios·音视频·实时音视频·m3u8·音视频在线播放
Flynt10 小时前
Linear 用 1000 个 PR 换掉 styled-components,我写了 200 个按钮,把这笔账复现了一遍
前端·css·preact
JavaGuide11 小时前
NVIDIA 又开源了!这次给 AI Agent 加上权限管控
前端·后端
excel11 小时前
prisma 如何处理数据库竞态
前端·数据库·后端
莪_幻尘13 小时前
Skill 体检:30 个 Skill 全凭感觉?体检器先自曝了 8 个“假 0 分
前端·人工智能·llm