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 中高级岗位很常见。

相关推荐
mldong2 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排3 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60613 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角4 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!4 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰5 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi6 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen7 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马8 小时前
AI源码分析:拆解模型底层实现逻辑
前端
IT_陈寒8 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端