大家好,很高兴又见面了,我是"高级前端?进阶?",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。
1.什么是 React Unforget
React Unforget 提供了一种优化 React 应用程序的替代方法,类似于 Preact 作为 React 的替代方案。 其不仅提供了React Compiler Forget 的后备选项,而且还突破了 React 生态界限,鼓励优化技术的创新和多样性。
本质上 React Unforget 是为了实现 React Compiler Forget 的功能,后者仍在开发中,发布日期不详。
本质上,React Unforget 是一个编译器,旨在通过智能缓存和优化来增强 React 应用程序的性能。 通过分析和改造 React 组件和 Hooks,React Unforget 旨在减少不必要的重新渲染并优化执行流程,从而缩小与 Svelte 等更高效框架的性能差距。
React Unforget 的转换过程包括两个主要步骤:
- 计算依赖图:初始步骤涉及从根块语句 (Root Block Statement) 创建一个片段 (Segment) 并执行依赖图遍历以了解各个代码段之间的相互依赖关系。
- 代码转换:基于依赖图,对代码段进行转换,以优化其执行并减少不必要的计算。
React Unforget 的典型特征包括:
- 智能组件和 Hooks 缓存 (Memoization):自动识别和缓存 React 组件和 Hooks,确保只发生必要的重新渲染,从而带来更高性能且更具可读性的代码。
- 粒度 JSX 元素展开:展开 JSX 元素并分别缓存每个元素和表达式,以实现更有效的优化,有效避免重复使用 React.memo
- 缓存前一次的返回:React Unforget 具有独特的功能,即使在组件函数中提前返回也能缓存值,从而无需重组代码以符合 Hooks 规则,确保在不改变组件逻辑流程的情况下进行优化。
目前 React Unforget 在 Github 通过 MIT 协议开源,是一个值得关注的前端项目。
2.使用 React Unforget 和不使用 React Unforget 的代码对比
在使用 React Unforget 之前,开发者通常需要使用各种 Hooks 来缓存结果,比如 memo、useMemo 等等,这些 Hooks 通过缓存的方式最大化减少组件重新渲染次数,提高应用程序性能。但是,这种显式声明的方式明显提高了开发者的准入门槛,认知成本较高,而且非常容易达不到理想效果甚至出错。
// 缓存组件,缓存函数等
const UglyComponent = memo(() => {
const data = useData();
const filteredData = useMemo(() => {
const items = [];
for (let i = 0; i < 1000000000; i++) {
items.push(data[i]);
}
}, [data]);
// 缓存 JSX ,需要指定各种依赖
const someComplexJsx = useMemo(() => (
<>
<DependentComponent1 data={filteredData} />
</>
), [dependency1, dependency2, filteredData]);
return <div>{someComplexJsx}</div>;
});
React Unforget 的出现使得背后缓存的工作全部交由编译器智能完成,开发者完全专注于代码的业务逻辑。比如下面的代码将比未使用 React Unforget 时简洁的多:
// 不用显式声明各种 memo 的Hooks
const NiceComponent = () => {
const data = useData();
const filteredData = [];
for (let i = 0; i < 1000000000; i++) {
filteredData.push(data[i]);
}
return (
<div>
<DependentComponent1 data={filteredData} />
</div>
);
}
3.如何在项目集成 React Unforget
React Unforget 的使用非常简单,只需要将下面的代码添加到 Babal 插件:
{
"plugins": ["@react-unforget/babel-plugin"]
}
如果使用 webpack 打包器,也可以将添加到 babel-loader 配置中:
module.exports = {
// 其他配置
module: {
rules: [
{
test: /\.js$/,
use: {
loader: "babel-loader",
options: {
plugins: ["@react-unforget/babel-plugin"],
},
},
},
],
},
};
babel 插件接受一些选项,比如:
- throwOnFailure:如果为 true则插件在无法分析组件 / Hooks 时将抛出错误。
- skipComponents:要跳过的组件名称数组
- skipComponentsWithMutation :如果为 true,插件将跳过具有突变变量的组件,例如 array.push() 或变量重新赋值。
参考资料
https://github.com/mohebifar/react-unforget
https://react-unforget.vercel.app/how-it-works
https://www.youtube.com/watch?v=CJmGxioyjPo