0%

React详解-Hooks & 性能优化

Hooks

使用规则

  • 只能在函数组件或自定义 Hook 的顶层调用
    不能在条件判断、循环、嵌套函数中调用,确保 Hook 调用顺序一致。
  • 自定义 Hook 命名必须以 use 开头
    例如 useStateuseFetch 等,方便区分普通函数和 Hook。

常用的 React Hooks

React 提供了多种内置的 Hooks,常用的包括:

  • useState:用于在函数组件中添加状态。
  • useEffect:用于处理副作用,如数据获取、订阅或手动 DOM 操作。
  • useContext:用于在组件中订阅 React 上下文。
  • useReducer:用于以 reducer 的方式管理复杂的状态逻辑。
  • useRef:用于访问 DOM 节点或保存可变值。
  • useMemo:用于缓存计算结果,优化性能。
  • useCallback:用于缓存函数实例,避免不必要的重新渲染。

useStateuseEffect 作用

useState
用来管理组件内部状态,返回当前状态和更新状态的函数。

1
const [count, setCount] = useState(0);

count 是当前状态值,setCount 是更新函数。

useEffect
用于处理副作用,比如数据请求、DOM 操作、订阅等。
可以模拟类组件的生命周期:

1
2
3
4
5
6
useEffect(() => {
// 相当于 componentDidMount 和 componentDidUpdate
return () => {
// 相当于 componentWillUnmount
};
}, [dependencies]); // 依赖项数组,控制副作用执行时机

useMemouseCallback 区别

  • useMemo
    缓存计算结果,避免因每次渲染导致的重复计算。

    1
    const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
  • useCallback
    缓存函数的引用,避免子组件因函数引用变化而重复渲染。

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

    性能优化

    一、如何避免不必要的重渲染

    React 组件的重新渲染会带来性能开销,避免无谓的重渲染是优化的关键。常用方法有:

    1. 使用 React.memo 缓存组件

    • React.memo 是高阶组件,类似于类组件的 PureComponent,对函数组件进行浅层 props 比较,只有 props 变化才重新渲染。

    • 示例:

      1
      2
      3
      4
      const MyComponent = React.memo(({ value }) => {
      console.log('render');
      return <div>{value}</div>;
      });
    • 适合传入简单数据的组件,复杂对象需要注意浅比较的局限。

    2. 使用 useCallback 缓存函数引用

    • 避免每次渲染都创建新的函数,导致子组件因 props 变化重新渲染。

    • 示例:

      1
      2
      3
      4
      5
      6
      7
      8
      const Parent = () => {
      const [count, setCount] = useState(0);
      const handleClick = useCallback(() => {
      setCount(c => c + 1);
      }, []);

      return <Child onClick={handleClick} />;
      }
    • 这样 Child 组件不会因为每次渲染都拿到新的函数引用而重复渲染。

    3. 使用 useMemo 缓存计算结果

    • 避免每次渲染都执行复杂计算,导致子组件因传入新对象或新数据而重新渲染。

    • 示例:

      1
      const expensiveResult = useMemo(() => computeExpensive(data), [data]);

    4. 拆分组件

    • 将大组件拆成多个小组件,减少状态变化时渲染范围。

    二、React.lazy 与 Suspense 的作用

    1. React.lazy

    • 用于实现组件的动态按需加载(代码分割),减小首屏加载体积。

    • 只有当组件真正需要渲染时才去加载对应的 JS 代码。

    • 示例:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      import React, { lazy, Suspense } from 'react';

      const LazyComponent = lazy(() => import('./LazyComponent'));

      function App() {
      return (
      <Suspense fallback={<div>Loading...</div>}>
      <LazyComponent />
      </Suspense>
      );
      }

    2. Suspense

    • 用于包裹 React.lazy 异步加载的组件,指定加载中的占位 UI(如加载动画或提示文字)。
    • 当异步组件未加载完成时,会展示 fallback 指定的内容。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    import React, { Suspense, lazy, useState } from 'react';

    // 使用 React.lazy 动态导入组件
    const LazyComponent = lazy(() => import('./LazyComponent'));

    function App() {
    const [show, setShow] = useState(false);

    return (
    <div>
    <button onClick={() => setShow(true)}>显示懒加载组件</button>

    {/* Suspense 包裹懒加载组件,fallback 显示加载时内容 */}
    {show && (
    <Suspense fallback={<div>加载中,请稍候...</div>}>
    <LazyComponent />
    </Suspense>
    )}
    </div>
    );
    }

    export default App;

    总结

    • React.lazy + Suspense 可以有效实现按需加载,提升应用性能,尤其适合大型应用和路由懒加载。