React Hooks

React Hooks知识点汇总 – 编程小白指南

React Hooks 知识点详解

编程小白也能看懂的React Hooks入门指南

什么是React Hooks?

React Hooks是React 16.8引入的新特性,它允许你在不编写类组件的情况下使用state和其他React特性。

简单来说,Hooks就是一些特殊的函数,让你能够”钩入”React的功能。

为什么需要Hooks? 以前使用类组件时,逻辑分散在各个生命周期方法中,代码难以复用和维护。Hooks让函数组件拥有了类组件的能力,同时使代码更简洁、更易复用。
1

useState – 状态管理

⚖️

通俗解释

useState就像给函数组件添加了一个记忆功能。它让函数组件能够记住一些信息(状态),当这些信息改变时,组件会自动重新渲染。

import { useState } from ‘react’;

function Counter() {
  // count是状态值,setCount是更新状态的函数
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
使用场景: 当你需要在组件中存储和更新数据时使用,比如表单输入、计数器、开关状态等。
注意: useState的初始值只在组件首次渲染时使用,后续重新渲染时会使用最新的状态值。
2

useEffect – 副作用处理

🔍

通俗解释

useEffect就像组件的”后厨”,它让你在组件渲染后执行一些额外的操作(副作用),比如数据获取、订阅事件、手动修改DOM等。

import { useState, useEffect } from ‘react’;

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  // 当userId改变时,获取用户数据
  useEffect(() => {
    const fetchUser = async () => {
      const response = await fetch(`/api/users/${userId}`);
      const data = await response.json();
      setUser(data);
    };
    fetchUser();

    // 清理函数(可选)
    return () => {
      console.log(‘清理工作’);
    };
  }, [userId]); // 依赖数组

  return <div>{user ? user.name : ‘Loading…’}</div>;
}
三种使用模式:
  • useEffect(() => {...}) – 每次渲染后都执行
  • useEffect(() => {...}, []) – 仅在组件挂载时执行一次
  • useEffect(() => {...}, [dep1, dep2]) – 当依赖项改变时执行
注意事项: 1. 避免在useEffect中执行阻塞渲染的操作
2. 如果依赖项是对象或数组,注意它们的引用变化可能导致useEffect频繁执行
3

useContext – 共享数据

📡

通俗解释

useContext就像组件间的”广播系统”,它让你在组件树中传递数据,避免了层层传递props的麻烦。

// 1. 创建Context
const ThemeContext = React.createContext(‘light’);

// 2. 提供Context值
function App() {
  return (
    <ThemeContext.Provider value=”dark”>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

// 3. 在子组件中使用Context
function Toolbar() {
  const theme = useContext(ThemeContext);
  return <div>当前主题: {theme}</div>;
}
使用场景: 主题切换、用户认证信息、多语言切换、全局状态管理等需要跨组件共享数据的场景。
注意: 当Context的值变化时,所有使用该Context的组件都会重新渲染,即使它们只使用了部分值。
4

useRef – 引用DOM和持久化值

📌

通俗解释

useRef就像给你的组件一个”储物柜”,可以存放一些东西,这些东西在组件重新渲染时不会丢失,而且改变它们不会触发重新渲染。

import { useRef, useEffect } from ‘react’;

function TextInput() {
  // 创建一个ref来存储input DOM元素
  const inputRef = useRef(null);

  // 存储一个不会导致重新渲染的值
  const renderCount = useRef(0);

  useEffect(() => {
    // 组件挂载后自动聚焦到输入框
    inputRef.current.focus();
    
    // 更新渲染次数(不会触发重新渲染)
    renderCount.current = renderCount.current + 1;
  }, []);

  return (
    <div>
      <input ref={inputRef} type=”text” />
      <p>组件渲染次数: {renderCount.current}</p>
    </div>
  );
}
主要用途:
  • 访问DOM元素(如聚焦输入框、获取元素尺寸)
  • 存储可变值而不触发重新渲染
  • 保存上一次的状态或props
注意: 修改useRef的current属性不会触发重新渲染。如果需要根据变化触发渲染,应该使用useState。
5

useMemo – 记忆计算结果

💾

通俗解释

useMemo就像给你的计算器加了一个”缓存功能”,它记住复杂计算的结果,只有当依赖项改变时才会重新计算,避免不必要的重复计算。

import { useMemo, useState } from ‘react’;

function ExpensiveComponent({ list }) {
  const [filter, setFilter] = useState(”);

  // 只有list或filter改变时,才会重新计算filteredList
  const filteredList = useMemo(() => {
    console.log(‘重新计算列表’);
    // 假设这是一个耗时的过滤操作
    return list.filter(item =>
      item.name.toLowerCase().includes(filter.toLowerCase())
    );
  }, [list, filter]);

  return (
    <div>
      <input
        value={filter}
        onChange={e => setFilter(e.target.value)}
      />
      {filteredList.map(item => (
        <div key={item.id}>{item.name}</div>
      ))}
    </div>
  );
}
何时使用:
  • 计算成本高的操作(如大型列表过滤、复杂计算)
  • 避免子组件不必要的重新渲染
  • 依赖项变化时才需要重新计算的值
注意: 不要滥用useMemo,因为记忆化本身也有开销。只在性能确实需要优化时才使用。
6

useCallback – 记忆函数

📞

通俗解释

useCallback就像给你的函数一个”身份证”,它记住函数本身,只有当依赖项改变时才返回新的函数,避免子组件不必要的重新渲染。

import { useState, useCallback } from ‘react’;

function ParentComponent() {
  const [count, setCount] = useState(0);
  const [value, setValue] = useState(”);

  // 只有count改变时才会返回新的increment函数
  const increment = useCallback(() => {
    setCount(c => c + 1);
  }, []); // 空依赖数组表示函数永远不会改变

  // 只有当value改变时才会返回新的handleChange函数
  const handleChange = useCallback((e) => {
    setValue(e.target.value);
  }, []);

  return (
    <div>
      <Child onIncrement={increment} />
      <input value={value} onChange={handleChange} />
      <p>计数: {count}</p>
    </div>
  );
}

// 使用React.memo避免不必要的重新渲染
const Child = React.memo(({ onIncrement }) => {
  console.log(‘子组件渲染’);
  return <button onClick={onIncrement}>增加</button>;
});
使用场景:
  • 将函数传递给子组件时(特别是使用React.memo优化的组件)
  • 作为useEffect的依赖项时
  • 大型列表中的事件处理函数
注意: useCallback(fn, deps) 相当于 useMemo(() => fn, deps)。两者区别在于useMemo返回计算值,useCallback返回函数本身。

useMemo vs useCallback

这两个Hook容易混淆,下面是对比说明:

useMemo

用途: 记忆计算结果

返回值: 计算得到的值

示例:

const memoizedValue = useMemo(
  () => computeExpensiveValue(a, b),
  [a, b]
);

useCallback

用途: 记忆函数本身

返回值: 函数

示例:

const memoizedCallback = useCallback(
  () => { doSomething(a, b); },
  [a, b]
);

关系

useCallback(fn, deps) 等同于:

useMemo(
  () => fn,
  deps
);

两者都是性能优化手段,避免不必要的计算或渲染。

自定义Hooks – 打造你自己的Hook

通俗解释

自定义Hook就像创建你自己的”工具包”,把组件间的共享逻辑提取出来,变成可复用的函数。自定义Hook是名字以”use”开头的函数。

// 自定义Hook:使用窗口宽度
import { useState, useEffect } from ‘react’;

function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);
    window.addEventListener(‘resize’, handleResize);
    
    // 清理函数
    return () => {
      window.removeEventListener(‘resize’, handleResize);
    };
  }, []);

  return width;
}

// 在组件中使用自定义Hook
function ResponsiveComponent() {
  const width = useWindowWidth();
  return <div>窗口宽度: {width}px</div>;
}
自定义Hook的好处:
  • 逻辑复用 – 多个组件共享相同逻辑
  • 代码组织 – 将复杂逻辑拆分为小函数
  • 可测试性 – 独立于组件的逻辑更容易测试
注意: 1. 自定义Hook必须以”use”开头
2. 每个组件使用Hook时都有独立的状态
3. 可以在自定义Hook中使用其他Hook

React Hooks让函数组件更加强大!希望这份指南能帮助你理解Hooks的核心概念。

学习建议:从useState和useEffect开始,逐步尝试其他Hook,最后学习自定义Hook。

祝你编程愉快!

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部