原创 寅时码 2025-11-04 08:30 重庆
还记得 2021 年 React Conf 上,React 团队首次展示了那个让人眼前一亮的项目——「React Forget」。当时我就想,终于!React 终于要解决那个让人头疼的性能问题了。
点击关注公众号,“技术干货” 及时达!
babel-plugin-react-compiler 1.0,这四年的等待让我深刻体会到了什么叫 "望眼欲穿"。React 的 "愚蠢":为什么我们需要手动优化?那些年我们写过的 "屎山" 代码在 React 的世界里,性能优化一直是个让人头疼的问题。每次组件的 state 或 props 发生变化,React 都会从根节点开始对比,判断哪些节点需要更新。这种机制导致了大量不必要的重新渲染。为了避免这些不必要的渲染,我们不得不在代码里写满这样的 「memo」 "屎山":Vue 的 "优雅":细粒度响应式更新再看看 Vue,人家是怎么做的:const ExpensiveComponent = React.memo(({ data, onUpdate }) => {const processedData = useMemo(() => {return data.map(item => ({...item,processed: expensiveCalculation(item)}))}, [data])const handleClick = useCallback(() => {onUpdate(processedData)}, [processedData, onUpdate])return (<div onClick={handleClick}>{processedData.map(item => (<Item key={item.id} data={item} />))}</div>)})
简洁、优雅、自动优化。Vue 的细粒度响应式更新机制能够自动追踪数据的变化,并仅更新受影响的组件。开发者无需手动进行复杂的优化操作,代码更加直观和高效。React Compiler:四年的等待终于有了结果从React Forget到babel-plugin-react-compiler2021 年,React 团队在 React Conf 上首次展示了 React Forget 项目。这个项目的目标很明确:通过编译器自动优化组件的渲染性能,让开发者无需手动添加<template><div @click="handleClick"><Itemv-for="item in processedData":key="item.id":data="item"/></div></template><script setup>const processedData = computed(() => {return data.value.map(item => ({...item,processed: expensiveCalculation(item)}))})const handleClick = () => {onUpdate(processedData.value)}</script>
React.memo、useCallback 和 useMemo 等优化代码。经过四年的打磨,这项技术终于以 babel-plugin-react-compiler 的形式与开发者见面,现已发布稳定版 1.0react.dev/learn/react…[1]www.npmjs.com/package/bab…[2]接下来配置一下 Vite,看看编译产物,先关闭代码混淆压缩import { useState } from 'react'export default function App() {const [count, setCount] = useState(0)return (<div className='h-screen w-screen flex justify-center items-center flex-col gap-8'><Comp1 /><button onClick={ () => setCount(count + 1) }>+</button><button onClick={ () => setCount(count - 1) }>-</button><p>{ count }</p><Comp2 /></div>)}function Comp1() {return <div class>Comp1 { Math.random() }</div>}function Comp2() {return <div class>Comp2 { Math.random() }</div>}
display: none 能解决一切,那只能说明的开发经验太浅了「display: none 的局限」:组件仍会渲染和初始化获取不到正确的 DOM 尺寸会触发生命周期和副作用多个隐藏组件会造成性能浪费以前我是自己封装 KeepAlive 组件,需要借助 Suspense 挂起渲染,或手动管理组件卸载,代码复杂且容易出问题,代码大致思路如下好起来了四年的等待,从 React Forget 到 babel-plugin-react-compiler,React 终于迎来了自动化的性能优化时代。并且还带来了 React 19.2 各项好特性,终于不是 「SHIT SSR」 了虽然 React 在性能优化方面曾经被诟病,虽然我们曾经写过无数的 "屎山" 代码,虽然 Vue 等框架在响应式更新方面确实更加优雅,但 React Compiler 的到来无疑为 React 开发者带来了福音。它通过自动化的性能优化,简化了开发流程,降低了出错的风险。开发者可以专注于业务逻辑,而无需担心性能优化的细节。四年的等待值得吗?我想说,值得。因为这意味着 React 正在迎头赶上,为开发者提供更高效、更便捷的开发体验。import type { KeepAliveProps } from './type'import { memo, Suspense, use } from 'react'import { KeepAliveContext } from './context'const Wrapper = memo<KeepAliveProps>(({ children, active }) => {const resolveRef = useRef<Function | null>(null)if (active) {resolveRef.current?.()resolveRef.current = null}else {throw new Promise((resolve) => {resolveRef.current = resolve})}return children})/*** 利用 Suspense 实现的 KeepAlive 组件* 当 active 为 false 时,抛异常,触发 Suspense 的 fallback* 当 active 为 true 时,resolve 异常,触发 Suspense 的正常渲染*/export const KeepAlive = memo(({uniqueKey: key,active,children,}: KeepAliveProps & { uniqueKey?: keyof any }) => {const { findEffect } = use(KeepAliveContext)/*** 触发钩子*/useEffect(() => {const { activeEffect, deactiveEffect } = findEffect(key)if (active) {activeEffect.forEach(fn => fn())}else {deactiveEffect.forEach(fn => fn())}}, [active, findEffect, key])return <Suspense fallback={ null }><Wrapper active={ active }>{ children }</Wrapper></Suspense>})
点击"阅读原文"了解详情~
