什么,React 的 jsx也能实现Vue3 模板的静态提升效果?🚀🚀🚀

674 阅读2分钟

我们知道 vue3 的到来,极大提升了vue的编译效率,一个重要的原因是采用了静态提升策略编译模版。

文章同步在公众号:萌萌哒草头将军,欢迎关注

静态提升是指,将模板中静态的内容标记出来,下次更新模板时,跳过diff阶段以此来提升渲染速度。

<div>
  <div>foo</div> <!-- 需提升 -->
  <div>bar</div> <!-- 需提升 -->
  <div>{{ dynamic }}</div>
</div>

那么react是否有类似的功能呢?坏消息是没有,好消息是可以通过babel插件实现。

react中如果jsx片段不依赖任何状态,那么可以定义为是静态的。

比如,一个简单的jsx文件如下:定义了一个Hr组件,和一个包含Hr组件的WithChildren组件。它们都是静态的。

const Hr = () => {
  return <hr className="hr" />;
};

const WithChildren = (props) => {
  return <div className={props.className}>
    <hr />
  </div>;
}

使用 jsx 方法解析成js文件后这样的:

import { jsx as _jsx } from "react/jsx-runtime";
const Hr = () => {
  return _jsx("hr", {
    className: "hr"
  });
};
const WithChildren = props => {
  return _jsx("div", {
    className: props.className,
    children: _jsx("hr", {})
  });
};

我们可以看到,即使我们已经生成了Hr组件,在生成WithChildren组件时,又重新生成了一次Hr组件,也就是类似于vue2没有静态提升的效果。

那么,我们应该怎么实现静态提升的效果呢?一个简单的想法立马浮现在了脑海里:短路符 ||

let val = null;
function createVal (val) {
    if (!val) {
        val = "your val"
    }
    return val
}
return val || createVal(val)

如果在上面的react示例中实现则如下:

var _hr, _hr2;
import { jsx as _jsx } from "react/jsx-runtime";
const Hr = () => {
  return _hr || (_hr = _jsx("hr", {
    className: "hr"
  }));
};
const WithChildren = props => {
  return _jsx("div", {
    className: props.className,
    children: _hr2 || (_hr2 = _jsx("hr", {}))
  });
};

实际上,这是bable插件@babel/plugin-transform-react-constant-elements的工作原理,更好的消息是,这个插件也是@babel/preset-react的预设插件,默认是开启的。

好了,今天的分享就到这了,希望可以帮助到你。

我创建了一个技术交流群,每天更新热门文章,感兴趣的小伙伴可以关注我~