React 17.0 RC 引入新的JSX转换

尽管之前React 17.0的主版本号已经说过了,17.0是一个没有新功能的,主要侧重于React本身的升级,把17.0比作一个垫脚石版本。昨天React发布了blog,提供了一套全新的JSX转换。我这里根据官方blog做一个简单地介绍。

什么是JSX转换?

大家应该都知道,现有的浏览器都是无法直接解译JSX的,所以大多数React用户都需要使用Babel或者TypeScript之类的编译器来将JSX转换为浏览器能够理解的JavaScript语言。许多预配置的工具箱(如:Create React App 或者Next.js)内部也有JSX的转换。
React 17.0的正式版发布在即,尽管React团队想对JSX的转换进行改进,但React团队不想打破现有的配置。这就是为什么React团队与Babel合作,为想要升级的开发者提供了一个全新的JSX转换的重写版本。
本次升级到新的版本是可选的,但升级它会为你带来一些好处:

  • 通过全新的转换,你可以单独使用JSX而无需引入React.
  • 根据你的配置,JSX的编译输出可能会稍微改善bundle的大小.
  • 它将实现未来的改进,减少你需要学习React概念的数量。
    此次升级不会改变JSX语法,因此不是必须的。旧的JSX转换将继续正常工作。没有计划取消对它的支持。
    React 17的RC版本已经引入了对全新的转换的支持。所以你可以尝试一下。为了让大家更容易使用,在React17发布之后,我们计划支持React 16.x, React 15.x和React 0.14.x。你可以在下面找到不同工具的升级说明。
    现在,让我们仔细看看新旧转换之间的区别。

新转换有何不同?

当你使用JSX时,编译器会将其转换为浏览器可以理解的React函数调用。旧的JSX转换将JSX转换为React.createElement(...)调用。
例如,假设源代码如下:

import React from 'react';

function App() {
  return <h1>Hello World</h1>;
}

在后台,旧的JSX转换为常规的javaScript:

import React from 'react';

function App() {
  return React.createElement('h1', null, 'Hello world');
}

注意
无需更改代码。我们将介绍JSX转换如何讲你的JSX源码转换为浏览器能理解的JavaScript代码。

但是,这并不完美:

  • 因为如果使用JSX,则需要在React的环境下,因为JSX会被编译成React.createElement.
  • 有一些React.createElement不允许做性能的改进和简化。

为了解决这些问题,React17在React包中引入了两个新的入口,这些入口只会被Babel和TypeScript等编译器使用。新的JSX转换没有将JSX转换为React.createElement,而是自动从React包中引入新的入口函数并调用。例如:

function App() {
  return <h1>Hello World</h1>;
}

现在将转换为:

// Inserted by a compiler (don't import it yourself!)
import {jsx as _jsx} from 'react/jsx-runtime';

function App() {
  return _jsx('h1', { children: 'Hello world' });
}

注意,此时源代码无需引入React即可使用JSX了!(但是我们任然需要导入React才能使用Hooks或者其他导出。)

此次变化与现在所有的JSX代码完全兼容,因此无需修改组件。如果你对此感兴趣,你可以查看RFC了解全新转换工作的具体细节。

注意
react/jsx-runtime和react/jsx-dev-runtime中的函数只能由编译器转换使用。如果需要在代码中手动创建元素,则应该继续使用React.createElement。他将继续工作,不会消失。

如何升级到新的JSX转换

如果你还没有准备好升级到全新的JSX转换,或者你正在为其他库使用JSX,请不要担心,旧的转换不会被删除,并将继续支持。
如果要升级,则需要两件事:

  • 一个支持全新转换的React版本(当前,只有React 17RC 支持它,但是在React17.0发布后,我们计划针对16.x 15.x 0.14.x发布兼容版本。)
  • 兼容的编译器(请看下面关于不同工具的说明)。

由于新的JSX转换不依赖React环境,我们准备了一个自动化脚本,该脚本将从您的代码中删除不必要的导入。

Create React App

Create React App 已对其做了兼容支持。并将在即将到来的V4.0版本中提供支持,该版本现在还处于测试阶段。

Next.js

Next.js的v9.5.3+会使用新的转换来兼容React版本。

Gatsby

Gatsby的v2.24.5+会使用新的转换来兼容React版本。

注意
如果在Gatsby遇到error,请升级到17.0.0-rc.2,请运行npm update以对其进行修复。

手动配置Babel

Babel v7.9.0及更高版本提供了对新JSX转换的支持。

首先,你需要更新至最新版本的Babel和transform插件。

如果您正在使用@babel/plugin-transform-react-jsx:

# for npm users
npm update @babel/core @babel/plugin-transform-react-jsx
# for yarn users
yarn upgrade @babel/core @babel/plugin-transform-react-jsx

如果您正在使用@babel/preset-react:

# for npm users
npm update @babel/core @babel/preset-react
# for yarn users
yarn upgrade @babel/core @babel/preset-react

当前,旧的转换("runtime": "classic")是默认选项。如果要启用新的转换,您可以将{"runtime": "automatic"}作为传递给@babel/plugin-transform-react-jsx或@babel/preset-react的选项:

// If you are using @babel/preset-react
{
  "presets": [
    ["@babel/preset-react", {
      "runtime": "automatic"
    }]
  ]
}
// If you're using @babel/plugin-transform-react-jsx
{
  "plugins": [
    ["@babel/plugin-transform-react-jsx", {
      "runtime": "automatic"
    }]
  ]
}

从Babel 8开始 "automatic"会将两个插件默认集成在runtime中。有关更多信息,请查看Babel文档中的@ babel / plugin-transform-react-jsx@ babel / preset-react

注意
如果你在使用JSX时,使用React以外的库,你可以使用importSource选项从该库中引入,前提是他提供了必要的入口。或者你可以继续使用经典的转换,它将继续被支持。

ESLint

如果你正在使用eslint-plugin-react,其中的react/jsx-uses-react和react/react-in-jsx-scope规则将不再需要,可以关闭或者删除它们。

{
  // ...
  "rules": {
    // ...
    "react/jsx-uses-react": "off",
    "react/react-in-jsx-scope": "off"
  }
}

TypeScript

TypeScript将在v4.1 beta中支持新的JSX转换。

Flow

Flow将在v0.126.0及更高版本中的新JSX转换。

删除未使用的React导入

因为新的JSX转换会自动引入必要的react/jsx-runtime函数,因此当你使用JSX时,将无需再引入React。这可能会导致你的代码中有未使用的React导入。保留它们并没有什么坏处,但是如果你想删除它们,我们建议运行“ codemod”脚本以自动删除它们:

cd your_project
npx react-codemod update-react-imports

注意
如果你在运行codemod时遇到错误,请在npx react-codemod update-react-imports要求您选择其他JavaScript环境。尤其是选择"javaScript with Flow"时,即使你没有使用Flow,也可以选择它。
请记住,在codemod输出并不总是匹配你的项目的编码风格,所以你可能需要运行Prettier在codemod结束后以保证编码风格一致。

运行此codemod将:

  • 升级到新的JSX转换后,删除所有未使用的React导入。
  • 改变所有的React的默认引入,更改为非结构化命名导入。例如:import React from "react" 改为import { useState } from "react",这将是未来的首选风格。codemod 不会影响import * as React from "react" 这也是一个有效的风格,磨人的导入将继续在React17中工作,但从长远来看,我们鼓励不再使用它们。
    例如:
import React from 'react';

function App() {
  return <h1>Hello World</h1>;
}

将被替换为:

function App() {
  return <h1>Hello World</h1>;
}

如果你使用了React的其他导入,比如hook,那么codemod将把他们转化为具名导入。
例如:

import React from 'react';

function App() {
  const [text, setText] = React.useState('Hello World');
  return <h1>{text}</h1>;
}

将被替换为:

import { useState } from 'react';

function App() {
  const [text, setText] = useState('Hello World');
  return <h1>{text}</h1>;
}

除了清理未使用的导入,次工具还可帮你为未来的React(不是React17)主要版本做准备,该版本将支持ES模块,并且没有默认导出。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,635评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,543评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,083评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,640评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,640评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,262评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,833评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,736评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,280评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,369评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,503评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,185评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,870评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,340评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,460评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,909评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,512评论 2 359