反应& React-router异步组件多次挂载(componentDidMount多次调用)

时间:2018-01-19 17:21:23

标签: javascript reactjs asynchronous react-router react-router-v4

我正在使用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 / chunk一代,因为在使用AsyncCOmponents并将我的代码拆分成块之前我没有遇到这个问题...但是我没有得到它来自的确切位置

非常感谢您的帮助

1 个答案:

答案 0 :(得分:2)

尝试在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提供可预测的生命周期。