App下載

React 17.0.0-rc.2 版本正式發(fā)布,引入了全新的 JSX 轉(zhuǎn)換

猿友 2020-09-28 11:04:25 瀏覽數(shù) (10970)
反饋

北京時間 9 月 23 日凌晨,React 團隊發(fā)布了關(guān)于全新 JSX 轉(zhuǎn)換的博客,同時發(fā)布了 React 17.0.0-rc.2 版本,新的 JSX 轉(zhuǎn)換不再依賴 React 環(huán)境,在轉(zhuǎn)換時會自動引入新的 runtime。

原文鏈接:reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html

作者:Luna Ruan

譯者:QC-L

譯文首發(fā)于 React 中文文檔博客,歡迎關(guān)注 https://zh-hans.reactjs.org 或者關(guān)注印記中文公眾號。

雖然 React 17 并未包含新特性[1],但它將提供一個全新版本的 JSX 轉(zhuǎn)換。本文中,我們將為你描述它是什么以及如何使用。

何為 JSX 轉(zhuǎn)換?

在瀏覽器中無法直接使用 JSX,所以大多數(shù) React 開發(fā)者需依靠 Babel 或 TypeScript將 JSX 代碼轉(zhuǎn)換為 JavaScript。許多包含預(yù)配置的工具,例如 Create React App 或 Next.js,在其內(nèi)部也引入了 JSX 轉(zhuǎn)換。

React 17 發(fā)布在即,盡管我們想對 JSX 的轉(zhuǎn)換進行改進,但我們不想打破現(xiàn)有的配置。于是我們選擇與Babel[2] 合作,為想要升級的開發(fā)者提供了一個全新版本的,重構(gòu)過的 JSX 轉(zhuǎn)換

升級至全新的轉(zhuǎn)換完全是可選的,但升級它會為你帶來一些好處:

  • 使用全新的轉(zhuǎn)換,你可以單獨使用 JSX 而無需引入 React。
  • 根據(jù)你的配置,JSX 的編譯輸出可能會略微改善 bundle 的大小
  • 它將減少你需要學(xué)習(xí) React 概念的數(shù)量,以備未來之需。

此次升級不會改變 JSX 語法,也并非必須。舊的 JSX 轉(zhuǎn)換將繼續(xù)工作,沒有計劃取消對它的支持。

React 17 的 RC 版本[3] 已經(jīng)引入了對全新 transform 的支持,所以你可以嘗試一下!為了讓大家更容易使用,在 React 17 正式發(fā)布后,我們還計劃將其支持 React 16.x,React 15.x 以及 React 0.14x。你可以在下方[4]找到不同環(huán)境的升級說明。

接下來,我們來仔細(xì)對比新舊轉(zhuǎn)換的區(qū)別。

新的轉(zhuǎn)換有何不同?

當(dāng)你使用 JSX 時,編譯器會將其轉(zhuǎn)換為瀏覽器可以理解的 React 函數(shù)調(diào)用。舊的 JSX 轉(zhuǎn)換會把 JSX 轉(zhuǎn)換為 React.createElement(...) 調(diào)用。

例如,假設(shè)源代碼如下:

import React from 'react';


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

舊的 JSX 轉(zhuǎn)換會將上述代碼變成普通的 JavaScript 代碼:

import React from 'react';


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

注意

無需改變源碼。我們將介紹 JSX 轉(zhuǎn)換如何將你的 JSX 源碼變成瀏覽器可以理解的 JavaScript 代碼。

然而,這并不完美:

  • 如果使用 JSX,則需在 React 的環(huán)境下,因為 JSX 將被編譯成 React.createElement。
  • 有一些 React.createElement 無法做到的 性能優(yōu)化和簡化[5]。

為了解決這些問題,React 17 在 React 的 package 中引入了兩個新入口,這些入口只會被 Babel 和 TypeScript 等編譯器使用。新的 JSX 轉(zhuǎn)換不會將 JSX 轉(zhuǎn)換為 React.createElement,而是自動從 React 的 package 中引入新的入口函數(shù)并調(diào)用。例如:

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

現(xiàn)在將轉(zhuǎn)換為:

// 由編譯器引入(禁止自己引入!)
import {jsx as _jsx} from 'react/jsx-runtime';


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

注意,此時源代碼無需引入 React 即可使用 JSX 了?。ǖ孕枰?React,以便使用 React 提供的 Hook 或其他導(dǎo)出。)

此變化與所有現(xiàn)有 JSX 代碼兼容,所以你無需修改組件。如果你對此感興趣,你可以查看 RFC[6] 了解全新轉(zhuǎn)換工作的具體細(xì)節(jié)。

注意

react/jsx-runtimereact/jsx-dev-runtime 中的函數(shù)只能由編譯器轉(zhuǎn)換使用。如果你需要在代碼中手動創(chuàng)建元素,你可以繼續(xù)使用 React.createElement。它將繼續(xù)工作,不會消失。

如何升級至新的轉(zhuǎn)換

如果你還沒準(zhǔn)備好升級為全新的 JSX 轉(zhuǎn)換,或者你正在為其他庫使用 JSX,請不要擔(dān)心,舊的轉(zhuǎn)換不會被移除,并將繼續(xù)支持。

如果你想升級,你需要準(zhǔn)備兩件事:

  • 支持新轉(zhuǎn)換的 React 版本(目前,只有 React 17 的 RC 版本[7] 支持它,但是 React 17.0 發(fā)布后,我們計劃針對 0.14.x、15.x 以及 16.x 做兼容。)
  • 一個兼容新轉(zhuǎn)換的編譯器(請看下面關(guān)于不同工具的說明)。

由于新的 JSX 轉(zhuǎn)換不依賴 React 環(huán)境,我們準(zhǔn)備了一個自動腳本[8],用于移除你代碼中不必要的引入。

Create React App

Create React App 已對其做兼容支持[9],并將在 即將發(fā)布的 v4.0 版本[10]中提供,該版本處于測試階段。

Next.js

Next.js 的 v9.5.3[11]+ 會使用新的轉(zhuǎn)換來兼容 React 版本。

Gatsby

Gatsby 的 v2.24.5[12]+ 會使用新的轉(zhuǎn)換來兼容 React 版本。

注意

如果你在 Gatsby 中遇到 error[13],請升級至 17.0.0-rc.2,運行 npm update 解決此問題。

手動配置 Babel

Babel 的 v7.9.0[14] 及以上版本可支持全新的 JSX 轉(zhuǎn)換。

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

如果你使用的是 @babel/plugin-transform-react-jsx

# npm 用戶
npm update @babel/core @babel/plugin-transform-react-jsx
# yarn 用戶
yarn upgrade @babel/core @babel/plugin-transform-react-jsx

如果你使用的是 @babel/preset-react

# npm 用戶
npm update @babel/core @babel/preset-react
# yarn 用戶
yarn upgrade @babel/core @babel/preset-react

目前,舊的轉(zhuǎn)換的默認(rèn)選項為("runtime": "classic")。如需啟用新的轉(zhuǎn)換,你可以使用 {"runtime": "automatic"} 作為 @babel/plugin-transform-react-jsx@babel/preset-react 的選項:

// 如果你使用的是 @babel/preset-react
{
  "presets": [
    ["@babel/preset-react", {
      "runtime": "automatic"
    }]
  ]
}
// 如果你使用的是 @babel/plugin-transform-react-jsx
{
  "plugins": [
    ["@babel/plugin-transform-react-jsx", {
      "runtime": "automatic"
    }]
  ]
}

從 Babel 8 開始,"automatic" 會將兩個插件默認(rèn)集成在 rumtime 中。欲了解更多信息,請查閱 Babel 文檔中的 @babel/plugin-transform-react-jsx[15] 以及 @babel/preset-react[16]。

注意

如果你在使用 JSX 時,使用 React 以外的庫,你可以使用 importSource 選項[17]從該庫中引入 — 前提是它提供了必要的入口?;蛘吣憧梢岳^續(xù)使用經(jīng)典的轉(zhuǎn)換,它會繼續(xù)被支持。

ESLint

如果你正在使用 eslint-plugin-react[18],其中的 react/jsx-uses-reactreact/react-in-jsx-scope 規(guī)則將不再需要,可以關(guān)閉它們或者刪除。

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

TypeScript

TypeScript 將在 v4.1 beta[19] 版本中支持新的 JSX 轉(zhuǎn)換。

Flow

Flow 將在 v0.126.0[20] 中支持新的 JSX 轉(zhuǎn)換。

移除未使用的 React 引入

因為新的 JSX 轉(zhuǎn)換會自動引入必要的 react/jsx-runtime 函數(shù),因此當(dāng)你使用 JSX 時,將無需再引入 React。將可能會導(dǎo)致你代碼中有未使用到的 React 引入。保留它們也無傷大雅,但如果你想刪除它們,我們建議運行 “codemod”[21] 腳本來自動刪除它們:

cd your_project
npx react-codemod update-react-imports

注意:

如果你在運行 codemod 時出現(xiàn)錯誤,請嘗試使用 npx react-codemod update-react-imports選擇不同的 JavaScript 環(huán)境。尤其是選擇 "JavaScript with Flow" 時,即使你未使用 Flow,也可以選擇它,因為它比 JavaScript 支持更新的語法。如果遇到問題,請告知我們[22]。

請注意,codemod 的輸出可能與你的代碼風(fēng)格并不匹配,因此你可能需要在 codemod 完成后執(zhí)行 Prettier[23] 以保證格式一致。

運行 codemod 會執(zhí)行如下操作:

  • 升級到新的 JSX 轉(zhuǎn)換,刪除所有未使用的 React 引入。
  • 改變所有 React 的默認(rèn)引入將被改為解構(gòu)命名引入(例如,import React from "react" 會變成 import { useState } from "react"),這將成為未來開發(fā)的首選風(fēng)格。codemod 不會 影響現(xiàn)有的命名空間引入方式(即 import * as React from "react"),這也是一種有效的風(fēng)格,默認(rèn)的引入將在 React 17 中繼續(xù)工作,但從長遠(yuǎn)來看,我們建議盡量不使用它們。

示例:

import React from 'react';


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

將被替換為

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

如果你使用了 React 的其他導(dǎo)出 — 比如 Hook,那么 codemod 將把它們轉(zhuǎn)換為具名導(dǎo)入。

示例:

import React from 'react';


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

會被替換為

import { useState } from 'react';


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

除了清理未使用的引入外,此工具還可幫你為未來 React 主要版本(不是 React 17 版本)做鋪墊,該版本將支持 ES 模塊,并且沒有默認(rèn)導(dǎo)出。

鳴謝

我們要感謝 Babel,TypeScript,Create React App,Next.js,Gatsby,ESLint 以及 Flow 的主要維護者為新 JSX 轉(zhuǎn)換提供的實現(xiàn)和整合。我們還要感謝 React 社區(qū)對相關(guān) RFC[24] 提供的反饋和討論。

參考資料

[1]并未包含新特性: /blog/2020/08/10/react-v17-rc.html

[2]Babel: https://babeljs.io/blog/2020/03/16/7.9.0#a-new-jsx-transform-11154httpsgithubcombabelbabelpull11154

[3]React 17 的 RC 版本: /blog/2020/08/10/react-v17-rc.html

[4]下方: #how-to-upgrade-to-the-new-jsx-transform

[5]性能優(yōu)化和簡化: https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md#motivation

[6]RFC: https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md#detailed-design

[7]React 17 的 RC 版本: /blog/2020/08/10/react-v17-rc.html

[8]我們準(zhǔn)備了一個自動腳本: #removing-unused-react-imports

[9]對其做兼容支持: https://github.com/facebook/create-react-app/pull/9645

[10]即將發(fā)布的 v4.0 版本: https://gist.github.com/iansu/282dbe3d722bd7231fa3224c0f403fa1

[11]v9.5.3: https://github.com/vercel/next.js/releases/tag/v9.5.3

[12]v2.24.5: https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/CHANGELOG.md#22452-2020-08-28

[13]Gatsby 中遇到 error: https://github.com/gatsbyjs/gatsby/issues/26979

[14]v7.9.0: https://babeljs.io/blog/2020/03/16/7.9.0

[15]@babel/plugin-transform-react-jsx: https://babeljs.io/docs/en/babel-plugin-transform-react-jsx

[16]@babel/preset-react: https://babeljs.io/docs/en/babel-preset-react

[17]importSource 選項: https://babeljs.io/docs/en/babel-preset-react#importsource

[18]eslint-plugin-react: https://github.com/yannickcr/eslint-plugin-react

[19]v4.1 beta: https://devblogs.microsoft.com/typescript/announcing-typescript-4-1-beta/#jsx-factories

[20]v0.126.0: https://github.com/facebook/flow/releases/tag/v0.126.0

[21]“codemod”: medium.com/@cpojer/effective-javascript-codemods-5a6686bb46fb

[22]告知我們: https://github.com/reactjs/react-codemod/issues

[23]Prettier: https://prettier.io/

[24]RFC: https://github.com/reactjs/rfcs/pull/107

以上就是W3Cschool編程獅關(guān)于React 17.0.0-rc.2 版本正式發(fā)布,引入了全新的 JSX 轉(zhuǎn)換的相關(guān)介紹了,希望對大家有所幫助。

0 人點贊