搜尋

首頁  >  問答  >  主體

"import * as React from 'react'; 與 import React from 'react'; 的異同"

<p>我注意到<code>React</code>可以這樣導入:</p> <pre class="brush:js;toolbar:false;">import * as React from 'react'; </pre> <p>...或這樣導入:</p> <pre class="brush:js;toolbar:false;">import React from 'react'; </pre> <hr /> <p>第一種方式導入了<code>react</code>模組的所有內容(請參閱:導入整個模組的內容)</p> <p>第二種方式只匯入了<code>default</code>模組匯出(見:匯入預設匯出)</p> <hr /> <p>這兩種方式似乎是不同且根本上不相容的。 </p> <p>為什麼它們都能運作? </p> <hr /> <p>請參考原始碼並解釋機制...我對了解這是如何工作感興趣。 </p> <hr /> <p><strong>更新</strong></p> <p>這不是重複的問題,不同於「import * as react from 'react' vs import react from 'react'的區別」</p> <p>那個問題是透過一般的ES6模組資訊回答的。 </p> <p>我問的是讓<code>react</code>模組能夠這樣運作的機制。它似乎與原始程式碼中的「hacky」匯出機制有關,但不清楚它如何使匯入整個模組和只匯入預設匯出到<code>React</code>的兩種方式都能與轉譯JSX等運作。 </p>
P粉596161915P粉596161915464 天前537

全部回覆(2)我來回復

  • P粉486138196

    P粉4861381962023-08-23 10:44:14

    你的 tsconfig.json 檔案中很可能設定了 "allowSyntheticDefaultImports": true,,這實際上讓編譯器對它認為無效的預設導入保持靜默。 Typescript 增加了 esModuleInterop,它基本上與 babel 在模組載入方面所做的事情相同。

    這使你能夠在導入的源代碼沒有預設導出時使用 ES6 預設導入。

    Typescript 在這方面是嚴格的(遵循規則),這就是為什麼它要求你使用 import * as React from 'react'。或要求你在基本配置中告訴它允許合成預設導入。

    更多相關資訊

    #

    回覆
    0
  • P粉023650014

    P粉0236500142023-08-23 00:04:25

    TL;DR

    實際上,ES的import語句import defaultimport *並不是同一回事,它們在這種情況下表現相同是因為React作者選擇以這種方式發布庫並在TypeScript(使用esModuleInterop)或Babel以及打包工具中使用相容層使其「正常工作」。根據ES6規範,它可能不應該正常工作,但是今天我們仍然處於JS模組混亂的時代,因此像Babel、TypeScript、Webpack等工具都試圖規範行為。

    更多細節:

    React不是一個ES6函式庫。如果你查看原始碼,你會在index.js#中看到這個:

    const React = require('./src/React');
    
    // TODO: decide on the top-level export form.
    // This is hacky but makes it work with both Rollup and Jest.
    module.exports = React.default || React;

    (注意註釋,即使在React原始碼中,他們也在努力解決ES6預設導出的兼容性問題。)

    module.exports =語法是CommonJS(NodeJS)的語法。瀏覽器無法理解這個語法。這就是為什麼我們使用像Webpack、Rollup或Parcel這樣的打包工具。它們理解各種模組語法,並產生應該在瀏覽器中工作的打包檔案。

    但是,儘管React不是一個ES庫,但是TypeScript和Babel都允許你像導入ES庫一樣導入它(使用import語法,而不是require()等) ,但是CJS和ES之間存在一些需要解決的差異。其中之一是export =可以提供你ES沒有規範相容的導入方式,例如將函數或類別作為模組導入。為了解決這些不相容性問題,Babel允許你以預設方式導入CJS模組,或以命名空間方式導入。 TypeScript以前不支援這樣做,但最近在esModuleInterop下新增了這個選項。因此,現在Babel和TypeScript都可以相當一致地允許使用預設或命名空間ES導入來導入CJS模組。

    對於Ty​​peScript來說,也取決於函式庫的類型定義是如何定義的。我不會詳細介紹,但你可以想像在某些情況下,由於轉譯器和打包工具的原因,特定的導入在運行時可以正常工作,但TypeScript在編譯時會出現錯誤。

    另一個值得一提的事情是,如果你查看React的建置程式碼,還有一個UMD模組版本以及CJS版本。 UMD版本包含一些複雜的執行時間程式碼,以使其在任何模組環境中(包括瀏覽器)正常運作。它主要用於在運行時僅包含React(即不使用打包工具)的情況下使用。 範例

    令人困惑嗎?是的,我也這麼認為。 :)

    回覆
    0
  • 取消回覆