背景
目前我们常见的有两种引入 react
的方法:
import React from 'react';
// vs
import * as React from 'react';
这两种写法目前都可以运行,但是同一个目的出现两种写法就容易产生分歧,本文主要阐述这两种写法的不同并给出我建议的写法。
便捷性
从便捷性角度来讲,无疑第一种方式要少打好多字符。另外如果我们要引用 react
包内的其它导出项时,第一种方式的有点更明显:
import React, { useState } from 'react';
export default function MyComponent() {
const [foo, setFoo] = useState();
return <div>{foo}</div>;
}
对比后一种写法:
import * as React from 'react';
export default function MyComponent() {
const [foo, setFoo] = React.useState();
return <div>{foo}</div>;
}
这里只能通过 React
命名空间来引用内部导出项。
或者也可以单独再导出一遍内部项:
import * as React from 'react';
import { useState } from 'react';
无论怎么写,都很难达到第一种写法的便捷性。
语法和语义
ES 语法里并没有命名空间的语法,export
关键字是作用于当前文件的,因此只有文件是在 ES Module 语义下的命名空间。
export default
只是 export
的一个特例,用于导出一个特殊的名字,并不能用来导出一个命名空间.有人还是习惯于用一个对象来模拟一个命名空间:
export default {foo, bar};
这种写法并不符合 ES Module 的方式,构建工具是无法进行静态分析,也无法进行 Tree Shaking。
更多关于 export default
的解释可以参考 《export default 真的有害吗?》。
从语义的角度来讲,第一种写法就是错误的,React
仅仅是作为一个命名空间存在的,我们并不会像使用一个值一样来使用 React
。从 React 16.13.0 开始,React 的导出方式也已经更正为 export {xxx, ...}
的形式了(commit)。
之所以第一种导入方式还可以使用,是因为目前 React 的构建产物是 Commonjs 规范的,webpack 等构建工具做了兼容。
自动导入
相对于语义的正确性,我觉得这一点便捷性是应该牺牲一下的,但是有没有在不牺牲语义的情况下获得便捷的方法?下面我们来聊聊自动导入。
正常情况,我们不需要使用 import * as
语法来导入一个包,但是 JSX 文件的编译需要 React
命名空间。既然 JSX 是语法层面的扩展,那么把这个命名空间的导入也放到语法层面去解决也是理所当然的。
babel-plugin-transform-react-jsx 的自动导入模式目前只在 React 17 中可用,针对之前的版本,我们可以使用非官方的 babel-plugin-auto-import 插件。
总结
如何导出决定如何导入。
按顺序简要列一下可选的导入方案:
- 【最佳方案】自动导入
- 【兼容性好】
import * as React from 'react';
- 【不再推荐】
import React from 'react';
思考题
下面两种导入样式的写法有什么区别?应该选择哪种?
import * as styles from './index.module.scss
import styles from './index.module.scss