React 中 useMemo 和 useEffect 的区别(计算与监听方面)

React 中 useMemo 和 useEffect 的区别(计算与监听方面)

useMemouseEffect 是 React 中两个重要的 Hook,它们在计算和监听方面有显著的不同:

核心区别对比

特性 useMemo useEffect
执行时机 在渲染期间同步执行 在渲染完成后异步执行
主要用途 缓存计算结果 处理副作用
返回值 返回计算结果 不返回值(可返回清理函数)
依赖变化时 立即重新计算 在下一次渲染后执行
对渲染的影响 参与当前渲染 不影响当前渲染,可能触发后续渲染

计算方面的区别

useMemo(用于计算)

jsx 复制代码
function CalculateSum({ a, b }) {
  // 在渲染期间同步计算,结果直接用于渲染
  const sum = useMemo(() => {
    console.log('计算a+b');
    return a + b;
  }, [a, b]);

  return <div>总和: {sum}</div>;
}

特点:

  • 计算是同步的,会阻塞渲染直到计算完成
  • 计算结果直接参与当前渲染
  • 适合需要立即使用计算结果的场景

useEffect(不适合纯计算)

jsx 复制代码
function BadCalculateExample({ a, b }) {
  const [sum, setSum] = useState(0);
  
  // 错误用法:计算延迟,会导致额外渲染
  useEffect(() => {
    setSum(a + b);
  }, [a, b]);

  return <div>总和: {sum}</div>;
}

问题:

  • 计算是异步的,会导致额外的渲染
  • 不适合纯计算场景,更适合副作用操作

监听方面的区别

useEffect(用于监听变化)

jsx 复制代码
function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  
  // 监听userId变化,发起数据请求
  useEffect(() => {
    let isMounted = true;
    
    fetchUser(userId).then(data => {
      if (isMounted) setUser(data);
    });
    
    return () => { isMounted = false }; // 清理
  }, [userId]);

  return <div>{user?.name}</div>;
}

特点:

  • 适合执行副作用(API调用、DOM操作等)
  • 可以返回清理函数
  • 不会阻塞渲染

useMemo(不适合副作用)

jsx 复制代码
function BadWatchExample({ userId }) {
  // 错误用法:useMemo不应该用于副作用
  useMemo(() => {
    fetchUser(userId).then(/* ... */);
  }, [userId]);

  return <div>...</div>;
}

问题:

  • React 不保证useMemo一定会执行
  • 可能被跳过或延迟执行
  • 违反Hook设计原则

正确使用场景示例

组合使用案例

jsx 复制代码
function ProductPage({ productId }) {
  // 1. 用useMemo缓存计算结果
  const productDetails = useMemo(() => 
    calculateDetails(productId), 
    [productId]
  );

  // 2. 用useEffect处理副作用
  useEffect(() => {
    trackPageView(productId);
    return () => trackPageLeave(productId);
  }, [productId]);

  // 3. 用useMemo避免不必要渲染
  const recommendations = useMemo(() => 
    <Recommendations productId={productId} />,
    [productId]
  );

  return (
    <div>
      <ProductInfo data={productDetails} />
      {recommendations}
    </div>
  );
}

性能影响对比

useMemo 的性能影响

  • 优点:避免重复计算,优化渲染性能
  • 缺点:记忆化本身有内存开销,过度使用可能适得其反

useEffect 的性能影响

  • 优点:不会阻塞渲染
  • 缺点:异步执行可能导致状态不一致,过度使用会导致频繁的渲染循环

何时选择哪个Hook

使用 useMemo 当:

✅ 需要缓存昂贵的计算结果

✅ 需要稳定的对象引用以避免子组件不必要渲染

✅ 计算值需要在当前渲染中立即使用

使用 useEffect 当:

✅ 需要响应状态变化执行副作用

✅ 需要访问DOM或执行API调用

✅ 需要设置/清理定时器、事件监听器等

常见误区

  1. 用 useEffect 做计算

    jsx 复制代码
    // ❌ 错误:会导致额外渲染
    const [sum, setSum] = useState(0);
    useEffect(() => { setSum(a + b) }, [a, b]);
    
    // ✅ 正确:使用useMemo
    const sum = useMemo(() => a + b, [a, b]);
  2. 用 useMemo 执行副作用

    jsx 复制代码
    // ❌ 错误:副作用应使用useEffect
    useMemo(() => { fetchData() }, [dep]);
    
    // ✅ 正确
    useEffect(() => { fetchData() }, [dep]);
  3. 过度使用 useMemo

    jsx 复制代码
    // ❌ 不必要的记忆化
    const name = useMemo(() => user.name, [user]);
    
    // ✅ 直接使用即可
    const name = user.name;

总结

useMemouseEffect 虽然都可以响应依赖变化,但设计目的完全不同:

  • 计算优先用 useMemo:同步计算,立即影响渲染
  • 监听优先用 useEffect:异步执行,处理副作用
相关推荐
o***Z44815 小时前
前端性能优化案例
前端
张拭心15 小时前
前端没有实际的必要了?结合今年工作内容,谈谈我的看法
前端·ai编程
姜太小白15 小时前
【前端】CSS媒体查询响应式设计详解:@media (max-width: 600px) {……}
前端·css·媒体
weixin_4111918415 小时前
flutter中WebView的使用及JavaScript桥接的问题记录
javascript·flutter
HIT_Weston15 小时前
39、【Ubuntu】【远程开发】拉出内网 Web 服务:构建静态网页(二)
linux·前端·ubuntu
百***060115 小时前
SpringMVC 请求参数接收
前端·javascript·算法
天外天-亮16 小时前
Vue + excel下载 + 水印
前端·vue.js·excel
起个名字逛街玩16 小时前
前端正在走向“工程系统化”:从页面开发到复杂产品架构的深度进化
前端·架构
用户479492835691516 小时前
React 渲染两次:是 Bug 还是 Feature?聊聊严格模式的“良苦用心”
前端·react.js·前端框架
用户479492835691516 小时前
Code Review 惊魂:同事的“优雅”重构,差点让管理员全部掉线
javascript