React & React-router 异步组件挂载多次(多次调用componentDidMount)
React & React-router async components mounted multiple times (componentDidMount called many times)
我正在使用 Webpack 3.7.1 和 React 15.6.1,并且正在动态加载不同的组件。
我做了什么
- 使用 AsyncComponent 和 import() 生成块并异步加载组件
- 正确配置 webpack.config 文件以便创建块(代码拆分)
问题
- 组件被重新渲染(安装)多次。如果我在任何组件的任何 componentDidMount() 中控制台记录某些内容,它会在我的控制台中出现 2 次或更多次!之前没有这样做:当我只是正常导入组件时 ...
我更改为异步组件之前的行为
- 组件已正确加载并且只安装了一次...
我的Webpack.config文件
module.exports = {
devServer: {
historyApiFallback: true
},
entry: {
app:"./src/index.js",
vendor: [
"axios",
"react",
"react-dom",
"react-redux",
"react-router",
"react-router-dom",
"redux"
]
},
output: {
path: __dirname + '/public/views',
filename: '[name].js',
chunkFilename: '[chunkhash].chunk.js',
publicPath: "/views/"
},
module: {
loaders: [
{
test: /\.js$/,
loader: "babel-loader",
exclude: [/node_modules/, /pdfmake.js$/]
},
{
test: /\.json$/,
loader: "json-loader"
}
]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
minChunks: Infinity
}),
new webpack.NamedModulesPlugin(),
new HtmlWebpackPlugin({
filename: __dirname + "/views/index.ejs",
template: __dirname + "/views/template.ejs",
inject: 'body',
chunks: ['vendor', 'app'],
chunksSortMode: 'manual'
}),
new PreloadWebpackPlugin({
rel: "preload",
include: ["vendor", "app"]
}),
new webpack.optimize.OccurrenceOrderPlugin(),
]
};
我的AppContainer.js文件
/**
* General container of the website
*/
class AppContainer extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log("MOUNTING APP CONTAINER")
}
render() {
const HomePage = AsyncComponent(() =>
import(/* webpackChunkName:"HomePage" */ "../components/homepage/homepage")
);
return (
<div>
<Switch>
<Route exact path="/" component={HomePage} />
</Switch>
</div>
);
}
}
组件本身更复杂(执行 API 个调用并且有更多的路由)但为了堆栈目的在此处对其进行了简化 ;)
我的AsyncComponent.js文件
import React, { Component } from "react";
export default function asyncComponent(importComponent) {
class AsyncComponent extends Component {
constructor(props) {
super(props);
this.state = {
component: null
};
}
async componentDidMount() {
const { default: component } = await importComponent();
this.setState({
component: component
});
}
render() {
const C = this.state.component;
return C ? <C {...this.props} /> : null;
}
}
return AsyncComponent;
}
我猜这个问题来自 AsyncComponents/chunks 代,因为在使用 AsyncCOmponents 并将我的代码分成块之前我没有遇到这个问题......但我不知道它到底来自哪里
非常感谢您的帮助
尝试将 HomePage
的声明移到 render
之外。 render
可以调用任意次数,返回的每个组件在 React 中看起来都不一样。
/**
* General container of the website
*/
const HomePage = AsyncComponent(() =>
import(/* webpackChunkName:"HomePage" */ "../components/homepage/homepage")
);
class AppContainer extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log("MOUNTING APP CONTAINER")
}
render() {
return (
<div>
<Switch>
<Route exact path="/" component={HomePage} />
</Switch>
</div>
);
}
}
一般来说,我建议不要在 React 组件中进行异步工作。您的渲染层应该是同步的,以便您的 UI.
具有可预测的生命周期
我正在使用 Webpack 3.7.1 和 React 15.6.1,并且正在动态加载不同的组件。
我做了什么
- 使用 AsyncComponent 和 import() 生成块并异步加载组件
- 正确配置 webpack.config 文件以便创建块(代码拆分)
问题
- 组件被重新渲染(安装)多次。如果我在任何组件的任何 componentDidMount() 中控制台记录某些内容,它会在我的控制台中出现 2 次或更多次!之前没有这样做:当我只是正常导入组件时 ...
我更改为异步组件之前的行为
- 组件已正确加载并且只安装了一次...
我的Webpack.config文件
module.exports = {
devServer: {
historyApiFallback: true
},
entry: {
app:"./src/index.js",
vendor: [
"axios",
"react",
"react-dom",
"react-redux",
"react-router",
"react-router-dom",
"redux"
]
},
output: {
path: __dirname + '/public/views',
filename: '[name].js',
chunkFilename: '[chunkhash].chunk.js',
publicPath: "/views/"
},
module: {
loaders: [
{
test: /\.js$/,
loader: "babel-loader",
exclude: [/node_modules/, /pdfmake.js$/]
},
{
test: /\.json$/,
loader: "json-loader"
}
]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
minChunks: Infinity
}),
new webpack.NamedModulesPlugin(),
new HtmlWebpackPlugin({
filename: __dirname + "/views/index.ejs",
template: __dirname + "/views/template.ejs",
inject: 'body',
chunks: ['vendor', 'app'],
chunksSortMode: 'manual'
}),
new PreloadWebpackPlugin({
rel: "preload",
include: ["vendor", "app"]
}),
new webpack.optimize.OccurrenceOrderPlugin(),
]
};
我的AppContainer.js文件
/**
* General container of the website
*/
class AppContainer extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log("MOUNTING APP CONTAINER")
}
render() {
const HomePage = AsyncComponent(() =>
import(/* webpackChunkName:"HomePage" */ "../components/homepage/homepage")
);
return (
<div>
<Switch>
<Route exact path="/" component={HomePage} />
</Switch>
</div>
);
}
}
组件本身更复杂(执行 API 个调用并且有更多的路由)但为了堆栈目的在此处对其进行了简化 ;)
我的AsyncComponent.js文件
import React, { Component } from "react";
export default function asyncComponent(importComponent) {
class AsyncComponent extends Component {
constructor(props) {
super(props);
this.state = {
component: null
};
}
async componentDidMount() {
const { default: component } = await importComponent();
this.setState({
component: component
});
}
render() {
const C = this.state.component;
return C ? <C {...this.props} /> : null;
}
}
return AsyncComponent;
}
我猜这个问题来自 AsyncComponents/chunks 代,因为在使用 AsyncCOmponents 并将我的代码分成块之前我没有遇到这个问题......但我不知道它到底来自哪里
非常感谢您的帮助
尝试将 HomePage
的声明移到 render
之外。 render
可以调用任意次数,返回的每个组件在 React 中看起来都不一样。
/**
* General container of the website
*/
const HomePage = AsyncComponent(() =>
import(/* webpackChunkName:"HomePage" */ "../components/homepage/homepage")
);
class AppContainer extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log("MOUNTING APP CONTAINER")
}
render() {
return (
<div>
<Switch>
<Route exact path="/" component={HomePage} />
</Switch>
</div>
);
}
}
一般来说,我建议不要在 React 组件中进行异步工作。您的渲染层应该是同步的,以便您的 UI.
具有可预测的生命周期