Skip to content

React 文档

导读与全书目录表:见同目录 01-React 入门:简介·特性与设计范式.md 开头。


react 的 hook 函数

react hooks 是 react 16.8 新增的特性,为函数组件拓展了新的功能,让函数组件也可以拥有和维护自己的状态,可以让我们在函数组件中定义和修改状态,可以在函数组件中模拟生命周期

内置 hook 函数

  1. 基础 hook
shell
useState(管理状态):允许你在函数组件中使用局部状态。它返回一个状态值和更新该状态值的函数
useEffect(处理副作用):允许你在函数组件中执行副作用操作(如数据获取、订阅管理、DOM 操作等)。可模拟类组件生命周期
useContext(访问上下文):用于访问 React context 在组件树中传递的数据,而不必通过每个组件传递 props。
  1. 高级 hook
shell
useReducer(处理复杂状态逻辑):用于更复杂的 state 逻辑,它接收一个 reducer 函数和初始状态,然后返回当前的状态和派发 action dispatch 函数
useCallback(记忆回调函数):用于返回一个 memoized 版本的回调函数,防止不必要的渲染。
useMemo(记忆计算结果):用于对计算结果进行记忆,避免在每次渲染时重复计算。
useRef:获取DOM(不会触发重新渲染)
useImperativeHandle:自定义暴露给父组件的 ref 实例(通常与 forwardRef 一起使用)
useLayoutEffect:与 useEffect类似,但是执行时机不同,在 DOM 更新后同步触发
useDebugValue:用于在 React DevTools 中显示自定义 Hook 的标签(调试用)
  1. React 18 新增 Hook
shell
useId:生成唯一的 ID(适用于无障碍访问和 SSR)
useSyncExternalStore:用于订阅外部数据源(如 Redux、Zustand 等状态管理库)
useInsertionEffect(React 18):类似于 useLayoutEffect,但会在 DOM 变更前同步执行(适用于 CSS-in-JS 库)

自定义 hook 函数

  1. hook 特点:返回的变量,如果只有一个状态和改变它的方法可以放在[] 数组中返回(有序简单),其他情况,比如多个的放在 {} 返回
  2. 使用自定义 Hook 的规则
shell
命名必须以 "use" 开头:这样 React 才能识别它是一个 Hook
只能在 React 函数组件或自定义 Hook 中调用 Hook
不要在循环、条件或嵌套函数中调用 Hook
超级关键:自定义 Hook 内若要把数据交给 React 驱动渲染,应通过 **`useState` / `useReducer`** 等官方 Hook 持有状态;不要只靠普通变量返回并期望触发重渲染
  1. 定义同步|异步 hook
js
// 本地存储 hooK
function useLocalStorage(key, initialValue) {
    const [storedValue, setStoredValue] = useState(() => {
        try {
            const item = window.localStorage.getItem(key);
            return item ? JSON.parse(item) : initialValue;
        } catch (error) {
            console.log(error);
            return initialValue;
        }
    });

    const setValue = (value) => {
        try {
            const valueToStore = value instanceof Function ? value(storedValue) : value;
            setStoredValue(valueToStore);
            window.localStorage.setItem(key, JSON.stringify(valueToStore));
        } catch (error) {
            console.log(error);
        }
    };

    return [storedValue, setValue];
}

// 获取窗口大小 hook
function useWindowSize() {
    const [windowSize, setWindowSize] = useState({
        width: window.innerWidth,
        height: window.innerHeight,
    });

    useEffect(() => {
        function handleResize() {
            setWindowSize({
                width: window.innerWidth,
                height: window.innerHeight,
            });
        }

        window.addEventListener('resize', handleResize);
        return () => window.removeEventListener('resize', handleResize);
    }, []);

    return windowSize;
}

// 异步 hook:所谓的异步不是要异步调用这个 hook,同步也可,因为返回的状态是响应式的,所以无需担心触发渲染问题
function useFetch(url) {
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);

    useEffect(() => {
        const fetchData = async () => {
            try {
                const response = await fetch(url);
                if (!response.ok) {
                    throw new Error('Network response was not ok');
                }
                const result = await response.json();
                setData(result);
            } catch (err) {
                setError(err);
            } finally {
                setLoading(false);
            }
        };

        fetchData();
    }, [url]);

    return { data, loading, error };
}
  1. 使用自定义 hook
js
function UserProfile({ userId }) {
  const { data: user, loading, error } = useFetch(`/api/users/${userId}`);
  const [theme, setTheme] = useLocalStorage('theme', 'light');
  const { width } = useWindowSize();

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div className={`profile ${theme}`}>
      <h1>{user.name}</h1>
      <p>Window width: {width}px</p>
      <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
        Toggle Theme
      </button>
    </div>
  );
}

解决了什么问题

  • 函数组件也可以拥有和维护自己的状态
  • react hooks 更加利于逻辑复用和逻辑组织

React Hooks 用过哪些?核心解决什么问题?

回答

shell
常用的 Hooks:useState(状态管理)、useEffect(副作用)、useContext(上下文)、useRef(保存引用)、useMemo/useCallback(性能优化);
核心解决的问题:① 让函数组件也能拥有状态和生命周期(不用写 class 组件);② 解决 class 组件生命周期混乱、逻辑复用难的问题(比如 HOC/Render Props 嵌套深,Hooks 逻辑更聚合)。

useEffect 怎么用?依赖项怎么处理?

shell
useEffect 是处理副作用的 Hooks,副作用包括:请求、DOM 操作、订阅 / 取消订阅等;
用法分三种:
1. 无依赖项:每次渲染后执行(对应 class componentDidMount + componentDidUpdate);
2. 有依赖项:依赖项变化时执行;
3. return 为函数卸载执行

useState 和 useRef 的区别

shell
核心区别:① useState 改变会触发组件重新渲染,useRef 改变不会;② useState 存的是 “状态”,useRef 存的是 “引用”(比如 DOM 节点、定时器 ID、跨渲染周期的变量);
场景:需要更新并触发渲染用 useState;只需要保存值、不触发渲染用 useRef(比如获取输入框 DOM、保存上一次的状态)。

Hooks 设计理念?解决什么问题?注意事项?为什么不能在条件语句中使用?

回答

shell
# 总结
Hooks 重构了 React 的状态逻辑复用方式,让代码更简洁、逻辑更内聚。其调用规则是为了保证 Hooks 状态与调用顺序的一致性,这是由内部实现机制决定的。

# 设计理念
以函数为中心,将相关逻辑(状态 + 副作用)聚合,而非按生命周期拆分。

# 解决问题
Hooks 让函数组件拥有状态和生命周期能力,解决类组件逻辑复用复杂(HOC/Render Props)、代码分散的问题;

# 注意事项
只能在函数组件或自定义 Hooks 中调用。且只能在顶层调用(不能在 if/for 中)

#为什么不能在条件语句中使用?
因为 React 通过链表顺序识别 Hooks,条件调用会导致链表错乱,无法匹配状态。