在没有显式导入的情况下将 React 组件拆分为单独的文件
Splitting React components in seperate files without explicite import
我正在编写一个基于 Ruby Sinatra 后端的 React 应用程序。 main.js 文件呈现应用程序:
import React from 'react';
import ReactDOM from 'react-dom';
import Galery from './components/Galery'
ReactDOM.render(
<Galery />,
document.getElementById('app')
);
我曾经将所有组件都放在一个文件中,但现在想将它们拆分成单独的文件。如果我在每个父组件文件中导入子组件,我只能做到这一点 运行,就像 Galery.js:
中这样
import React, { Component } from 'react';
import Image from 'Image'
class Galery extends Component {
...
<Image ... />
...
}
是否可以避免显式导入所需的组件,而是将它们加载到 main.js 文件中?每个文件不导入Component模块也可以。
这是我的 webpack 配置:
module.exports = {
entry: './react/main.js',
output: {
path: __dirname,
filename: './public/bundle.js'
},
resolve: {
root: __dirname,
alias: {
},
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [
{
loader: 'babel-loader',
query: {
presets: ['react', 'es2015']
},
test: /\.js$/,
exclude: /(node_modules|bower_components)/
}
]
}
};
简答:
强烈建议在任何需要的地方使用显式导入,因为像 webpack
这样的工具通过删除不使用的函数来围绕包大小进行智能优化。请记住这一点,最简短的答案是:您使用 webpack + babel + React 的方式,无法避免为每个文件定义 imports
。
更长的答案:
是的,您可以做到,但这并不直接。与 Ruby 不同,constant/variable 查找在 JavaScript 中的工作方式不同。在 Ruby 中,以下工作正常:
# a.rb
A = 10
# b.rb
require "./a.rb"
puts a # => 10
这是因为当文件 a.rb
被解析并包含到 b.rb
中时,没有在 Ruby 中创建额外的子命名空间。所有顶级单位都存在,就好像它们是在 b.rb
中定义的一样。 More on this
为了将其与 JS 进行比较,我需要稍微了解一下模块包含的工作方式。到目前为止,这是一个相当复杂的情况。让我们首先考虑 NodeJS。在这个非浏览器环境中,还没有实现 import
功能,除了带有额外标志的前沿版本(截至今天的第 9 版)。所以当你使用像 webpack
和 import
这样的东西时,内部发生的是它们被转换为 webpack 自己的 require
shim。 import
和 require
的转换方式略有不同,因为前者是 "static" 样式加载器,而后者是动态样式加载器。在最基本的层面上,这意味着 import
语句应该在文件的顶部,而 require
语句可以在任何地方,当解释器遇到该行时,文件解析就会发生。这会产生奇怪的效果,如下所示。
NodeJS require
的工作方式是从包含的文件中识别一个 module.exports
对象。该对象指定哪些 functions/objects 暴露在外面。因此,与 Ruby 不同,已经存在 module.exports
的隐式本地命名空间(或者如果您愿意,可以分组),而不是全局 $LOADED_FEATURES
命名空间:
// a.js
const a = 10;
module.exports = { a: a };
// b.js
const a = require('./a.js');
console.log(a); // { a: 10 };
解决这个问题的一种方法是使用全局变量。就像 Ruby 一样,JavaScript 有一个隐式的全局命名空间——尤其是在浏览器中通过 window
和 NodeJS 中的 global
更常见。一种想法如下:
// main.js
import React from 'react';
import ReactDOM from 'react-dom';
import Image from 'components/image.js';
import Gallery from 'components/gallery.js';
window.React = React;
window.ReactDOM = ReactDOM;
window.Image = Image;
window.Gallery = Gallery;
// gallery.js
export default class Gallery extends React.Component {
render() {
return <Image />;
}
}
但是,这不起作用。为了模拟实际的 ES6 import
功能——这是一组静态定义的文件和函数,webpack 尝试通过 webpack 自己的 require
函数来模拟它们。并且这不会在导入完成时使全局附加常量可用。因此,为了使这项工作有效,一个解决方法是使用旧的 require
样式加载,这会改变 webpack 自己的 require
函数的工作方式。通过将以上内容更改为:
// main.js
const React = require('react');
const ReactDOM = require('react-dom');
window.React = React;
window.ReactDOM = ReactDOM;
const Image = require('components/image.js').default;
const Gallery = require('components/gallery.js').default;
window.Image = Image;
window.Gallery = Gallery;
// gallery.js
export default class Gallery extends React.Component {
render() {
return <Image />;
}
}
如您所见,获得 JavaScript 应用程序 运行 的工作量太大了。但主要问题是 webpack 无法进行任何智能优化,因为它不知道您没有使用哪些功能。所以最好避免做这一切。
我正在编写一个基于 Ruby Sinatra 后端的 React 应用程序。 main.js 文件呈现应用程序:
import React from 'react';
import ReactDOM from 'react-dom';
import Galery from './components/Galery'
ReactDOM.render(
<Galery />,
document.getElementById('app')
);
我曾经将所有组件都放在一个文件中,但现在想将它们拆分成单独的文件。如果我在每个父组件文件中导入子组件,我只能做到这一点 运行,就像 Galery.js:
中这样import React, { Component } from 'react';
import Image from 'Image'
class Galery extends Component {
...
<Image ... />
...
}
是否可以避免显式导入所需的组件,而是将它们加载到 main.js 文件中?每个文件不导入Component模块也可以。
这是我的 webpack 配置:
module.exports = {
entry: './react/main.js',
output: {
path: __dirname,
filename: './public/bundle.js'
},
resolve: {
root: __dirname,
alias: {
},
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [
{
loader: 'babel-loader',
query: {
presets: ['react', 'es2015']
},
test: /\.js$/,
exclude: /(node_modules|bower_components)/
}
]
}
};
简答:
强烈建议在任何需要的地方使用显式导入,因为像 webpack
这样的工具通过删除不使用的函数来围绕包大小进行智能优化。请记住这一点,最简短的答案是:您使用 webpack + babel + React 的方式,无法避免为每个文件定义 imports
。
更长的答案:
是的,您可以做到,但这并不直接。与 Ruby 不同,constant/variable 查找在 JavaScript 中的工作方式不同。在 Ruby 中,以下工作正常:
# a.rb
A = 10
# b.rb
require "./a.rb"
puts a # => 10
这是因为当文件 a.rb
被解析并包含到 b.rb
中时,没有在 Ruby 中创建额外的子命名空间。所有顶级单位都存在,就好像它们是在 b.rb
中定义的一样。 More on this
为了将其与 JS 进行比较,我需要稍微了解一下模块包含的工作方式。到目前为止,这是一个相当复杂的情况。让我们首先考虑 NodeJS。在这个非浏览器环境中,还没有实现 import
功能,除了带有额外标志的前沿版本(截至今天的第 9 版)。所以当你使用像 webpack
和 import
这样的东西时,内部发生的是它们被转换为 webpack 自己的 require
shim。 import
和 require
的转换方式略有不同,因为前者是 "static" 样式加载器,而后者是动态样式加载器。在最基本的层面上,这意味着 import
语句应该在文件的顶部,而 require
语句可以在任何地方,当解释器遇到该行时,文件解析就会发生。这会产生奇怪的效果,如下所示。
NodeJS require
的工作方式是从包含的文件中识别一个 module.exports
对象。该对象指定哪些 functions/objects 暴露在外面。因此,与 Ruby 不同,已经存在 module.exports
的隐式本地命名空间(或者如果您愿意,可以分组),而不是全局 $LOADED_FEATURES
命名空间:
// a.js
const a = 10;
module.exports = { a: a };
// b.js
const a = require('./a.js');
console.log(a); // { a: 10 };
解决这个问题的一种方法是使用全局变量。就像 Ruby 一样,JavaScript 有一个隐式的全局命名空间——尤其是在浏览器中通过 window
和 NodeJS 中的 global
更常见。一种想法如下:
// main.js
import React from 'react';
import ReactDOM from 'react-dom';
import Image from 'components/image.js';
import Gallery from 'components/gallery.js';
window.React = React;
window.ReactDOM = ReactDOM;
window.Image = Image;
window.Gallery = Gallery;
// gallery.js
export default class Gallery extends React.Component {
render() {
return <Image />;
}
}
但是,这不起作用。为了模拟实际的 ES6 import
功能——这是一组静态定义的文件和函数,webpack 尝试通过 webpack 自己的 require
函数来模拟它们。并且这不会在导入完成时使全局附加常量可用。因此,为了使这项工作有效,一个解决方法是使用旧的 require
样式加载,这会改变 webpack 自己的 require
函数的工作方式。通过将以上内容更改为:
// main.js
const React = require('react');
const ReactDOM = require('react-dom');
window.React = React;
window.ReactDOM = ReactDOM;
const Image = require('components/image.js').default;
const Gallery = require('components/gallery.js').default;
window.Image = Image;
window.Gallery = Gallery;
// gallery.js
export default class Gallery extends React.Component {
render() {
return <Image />;
}
}
如您所见,获得 JavaScript 应用程序 运行 的工作量太大了。但主要问题是 webpack 无法进行任何智能优化,因为它不知道您没有使用哪些功能。所以最好避免做这一切。