很多react开发者都听过这样一个说法:"React很快,因为它能高效地重新渲染。"
但实际情况可能让你意外——React并不是天生就快。它只是比较"宽容"。
如果你的状态设计不够仔细,React的虚拟dom很容易成为性能瓶颈。应用越复杂,那些不必要的重渲染代价就越大。
今天我们来聊聊重渲染发生的原因、避免方法,以及什么才是真正的"响应式"开发。
React的每次渲染都会触发一系列操作:
组件函数重新执行
Hook重新计算
JSX进行差异比较
子组件也可能跟着重渲染
虽然这些都是虚拟操作,但并不免费。当应用扩展到几百个组件时,这些微小的重渲染会累积起来,特别是在使用全局状态或Context时。
很多开发者为了"简单",把所有状态都放到Context或Redux中。但问题是:任何一个值的改变都会触发所有消费者的重渲染,即使它们并不关心这个特定的状态。
看看这个常见模式:
const ThemeContext = createContext();
function App() {
  return (
    <ThemeContext.Provider value={{ darkMode, toggleDarkMode }}>
      <Header />
      <Sidebar />
      <Content />
    </ThemeContext.Provider>
  );
}即使只有Header组件使用darkMode,当darkMode改变时,Provider里的所有子组件都会重渲染。这就是典型的"千次重渲染"问题。
你可能会想:"那我用memo把一切都包起来。"
记忆化确实有用,但它也有自己的代价:
React.memo()只在props浅比较相等时阻止重渲染
useMemo()和useCallback()能缓存计算,但增加了复杂性和内存开销
如果你把半个组件树都用React.memo()包装,其实是在对抗React,而不是优化它。
更好的解决方案是状态本地化——让状态尽可能靠近使用它的地方。
状态划分得越细,需要重渲染的组件就越少。
这就是为什么Zustand、Jotai、Valtio这些库很有效——它们让组件只订阅需要的数据。
看看Zustand的例子:
const useStore = create(set => ({
  count: 0,
  increment: () => set(state => ({ count: state.count + 1 })),
}));
function Counter() {
  const count = useStore(state => state.count);
  return <p>{count}</p>;
}这样,只有使用count的组件会重渲染,而不是整个应用。这才是真正的响应式,而不是依赖协调过程。
React的模型比较粗放:状态改变时重渲染整个组件。但新的范式(如Solid.js的信号、Qwik,甚至React Canary版本)使用细粒度响应式——只更新依赖改变数据的具体DOM节点。
这种转变大幅降低了重渲染的代价,让UI感觉瞬间响应。
如果说React 18关注的是并发,那么React 19+将更关注响应式。
看不见的东西就优化不了。使用React开发者工具的"Profiler"来测量重渲染发生的位置,结果常常让人惊讶。
重点关注这些情况:
找到性能热点问题,就解决了一半问题。
当React应用感觉慢时,问题很少出在算法上,通常是因为渲染流程不合理。真正的性能来自于围绕响应式数据流来构建应用,而不仅仅是更快的差异比较。
重点不是"阻止重渲染",而是让每次渲染都有价值。
根据项目经验,我总结了一些实用建议:
1. 状态设计要合理
局部状态用useState
跨组件状态根据共享范围选择方案
全局状态用状态管理库
2. 组件拆分要适度
不要把太多逻辑塞进一个组件。合理的组件划分能减少不必要的重渲染。
3. Context使用要谨慎
Context适合变化不频繁的数据,比如主题、用户信息。对于频繁更新的数据,考虑其他方案。
4. 列表渲染要加key
不仅是出于React要求,更是为了性能。稳定的key能帮助React准确识别元素变化。
5. 依赖数组要准确
useEffect、useMemo、useCallback的依赖数组要如实填写,避免过时闭包问题。
很多开发者(包括以前的我)把"性能优化"等同于"记忆化"。但性能不是来自避免渲染,而是理解渲染发生的时机和原因。
React不会拖慢你的应用——是你的架构设计可能有问题。
不要到处使用useMemo。应该重点设计状态本地化、响应式数据流和精确订阅。
这就是现代UI实现"快速"的方式——不是跳过渲染,而是智能地渲染。
在你的项目中,你是怎么处理重渲染的?更多地依赖记忆化,还是状态本地化模式?
欢迎分享你的经验,让我们把这变成一次有意义的交流,而不仅仅是另一篇React文章。
记住,好的性能来自于对框架工作原理的深入理解,而不是机械地应用所谓的最佳实践。每次当你考虑优化时,先测量,再优化,用数据说话。
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!
 在使用vue的时候,我们都知道它是双向数据绑定的,但是在使用不熟的情况下,经常会遇到:data中的数据变化了,但是并没有触发页面渲染。下面就整理一些出现这种情况的场景以及解决办法。
 这里结合art-template模板引擎说明。首先了解下前端页面中如何使用art-template。当不需要对SEO友好的时候,推荐使用客户端渲染;当需要对 SEO友好的时候,推荐使用服务器端渲染
 在使用vue的时候,偶然发现多次刷新或者网络加载缓慢的时候,会一瞬间出现设置的模板的情况。实在很影响美观,可以使用vue现成的指令来解决这个问题:v-cloak
 大部分Web应用的富文本内容都是以HTML字符串的形式存储的,通过HTML文档去展示HTML内容自然没有问题。但是,在微信小程序(下文简称为「小程序」)中,应当如何渲染这部分内容呢?
估计大家都听过,尽量将 CSS 放头部,JS 放底部,这样可以提高页面的性能。然而,为什么呢?大家有考虑过么?很长一段时间,我都是知其然而不知其所以然,强行背下来应付考核当然可以,但实际应用中必然一塌糊涂
原生JS改变页面数据,必须要获取页面节点,也即是进行DOM操作,jQuery之类的框架只是简化DOM操作的写法,实质并没有改变操作页面数据的底层原理,DOM操作影响性能(导致浏览器的重绘和回流),Vue是一个mvvm框架(库),大幅度减少了DOM操作
在决定渲染方式时,需要测量和理解真正的瓶颈在哪里。静态渲染或服务器渲染在多数情况都比较适用,尤其是可交互性对JS依赖较低的场景。下面是一张便捷的信息图,显示了服务器到客户端的技术频谱:
如果从服务端返回的数据量较少,或者只有几个字段,可以用vue的set方法,如果数据量较大,请直接看第二种情况。官网API是这样介绍的:Vue.set(target,key,value)
当数据需要异步加载时render获取不到数据可能会报一些错误,此时需要在render函数中加一个判断.行到render时,state对象的haveData为false, 所以此时页面展示 loading,当异步获取数据成功时
在vue.js中,要将一段字符串渲染成html,可以使用v-html指令。但是 官方文档 中的v-html部分也提醒了
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!