为什么函数式组件需要引进React?

作者:孙宇晨 来源:www.5idf.cn 2020-02-27   阅读:

在编写组件时,最让我迷惑的是在我编写纯函数组件,为什么没有在代码里面调用React 都需要导入React。经过一番调研,我发现是因为JSX 转译的设定。不过,人是比较懒惰的,透过安装babel-plugin-react-require 插件,达到自动导入React 的效果。这篇文章将会讲述我的调研经历和一点反思。

比如说我们有一个App.js 的文件,这里相等于Hello World 的设定。

import React from "react";
const App = () => (
  <div>Hello World!!!</div>
);
export default App;

原因

在Babel转译我们的App.js的时候,会把JSX语法糖转换为React.createElement方法。

var App = function App() {
  return React.createElement(
    "div",
    null,
    "Hello World!!!"
  );
};

你可以在Babel REPL来看到Babel是如何转译。

自动引入React

对于React系统的前端项目来说,我们能不能直接写纯函数组件,而不需要在顶部引进React语句:import React from 'react';

答案也是可以的,我们可以透过babel-plugin-react-require来自动辨认无状态组件,然后如果是的话,自动引进React。

安装方法

我们可以透过npm 直接安装

npm install babel-plugin-react-require --save-dev

然后在.babelrc加入react-require

{
  "plugins": [
    "react-require"
  ]
}

值得注意的是,react-require需要在transform-es2015-modules-commonjs之前引入,因为插件需要ES2015模块化语句来导入React到域里面。

例子

如果我们写了一个纯函数组件,代码如下:

export default function Component() {
  return (
    <div />
  );
}

babel-plugin-react-require 插件会自动将上面的代码转译为下面的代码:

import React from 'react';

export default function Component() {
  /* 下面的代碼交給 Babel 繼續編譯 */
  return (
    React.createElement('div')
  );
}

自定义转译使用方法

那么我们可以再想一下,如果用的不是React,而是其他React 生态圈里面的方法的话。比如说deku,它是一个用来使用纯函数和虚拟DOM 渲染界面的工具库。它也是React 生态圈里面的一份子。

我们能不能改写转译后的方法,不使用React.createElement方法?

答案是可以的。

@babel/plugin-transform-react-jsx允许我们在文件的顶部加入/** @jsx 方法名稱 */,或者是在.babelrc 全局修改

比如说这样的代码:

/** @jsx dom */

var { dom } = require("deku");

var profile = <div>
  <img src="avatar.png" className="profile" />
  <h3>{[user.firstName, user.lastName].join(' ')}</h3>
</div>;

会转译为下面的代码:

/** @jsx dom */

var dom = require("deku").dom;

var profile = dom("div", null,
  dom("img", { src: "avatar.png", className: "profile" }),
  dom("h3", null, [user.firstName, user.lastName].join(" "))
);

React 碎片

那么React 16.2.0新增的Fragments呢?我们可以透过/** @jsxFrag 函數名稱 */来达到转译后的修改目的。

输入:

/** @jsx dom */
/** @jsxFrag DomFrag */

var { dom, DomFrag } = require("deku");

var descriptions = items.map(item => (
  <>
    <dt>{item.name}</dt>
    <dd>{item.value}</dd>
  </>
));

输出:

/** @jsx dom */
/** @jsxFrag DomFrag */

var { dom, DomFrag } = require("deku");

var descriptions = items.map(item => dom(
  DomFrag,
  null,
  dom("dt", null, item.name),
  dom("dd", null, item.value)
));

你可以打开Babel REPL - React Fragment来实时调试代码。

安装方法

你需要安装@babel/plugin-transform-react-jsx来转换JSX语法,如果没有安装的话,那么你可以透过npm安装它。

npm install --save-dev @babel/plugin-transform-react-jsx

全局修改

.babelrc写入下面的片段:

{
  "plugins": ["@babel/plugin-transform-react-jsx"]
}

我们可以透过全局修改pragma来修改React.createElement,

{
  "plugins": [
    ["@babel/plugin-transform-react-jsx", {
      "pragma": "dom", // React.createElement
      "pragmaFrag": "DomFrag", // React.Fragment
      "throwIfNamespace": false, // 如果 XML 名稱空間的標籤名稱被使用的話,拋出異常
      "useBuiltIns": false // 使用 Object.assign 而不是 Babel 內建的擴展工具 (extend)
    }]
  ]
}

参考资料

  1. Why import React from “react” in a functional component?
  2. @babel/plugin-transform-react-jsx
  3. anthonyshort/deku - Github
  4. vslinko/babel-plugin-react-require - Github
分享给小伙伴们:
如果本文侵犯了您的权利, 请联系本网立即做出处理,谢谢。
当前位置:孙宇晨博客 > 技术 > 《为什么函数式组件需要引进React?转载请注明出处。
相关文章
  • 聚合物电容,为什么越来越多被选用?

    聚合物电容,为什么越来越多被选用?

  • 为什么有时候我们在电路中串联220Ω电阻

    为什么有时候我们在电路中串联220Ω电阻

  • 为什么表贴陶瓷电容一般什么都不印?

    为什么表贴陶瓷电容一般什么都不印?

  • 为什么有的电容即叫NPO,又叫C0G?

    为什么有的电容即叫NPO,又叫C0G?