JM:I have a dream,期待和你一起去实现!
原文及译文
JM
网友:Louis

        我正在使用Webpack 3.7.1和React 15.6.1,我正在动态加载不同的组件。我做了什么使用AsyncComponent和import()异步生成块和加载组件正确配置了webpack.config文件...

推荐:想去Google查资料?(你懂的)想建站?想测试?想挂机?想折腾?想要高性价比的服务器?点我!!


应对(React & React-router async components mounted multiple times (componentDidMount called many times))

我正在使用Webpack 3.7.1和React 15.6.1,我正在动态加载不同的组件。

What i did Using AsyncComponent and import() to generate the chunks and load components asynchronously Configured the webpack.config file properly so that the chunks are created (code splitting) The issue The components are rerendered (mounted) multiple times. If I console log something in any of the componentDidMount() of any components, it appears in my console 2 or more times !It was not doing so before : when I was just importing normally the component ... The behaviour before I change to async components The components were loaded correctly and mounted only one time ... My Webpack.config file
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(),
  ]
};
My AppContainer.js file
 /**
 * 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调用,并有更多的路由),但为了堆栈的目的,这里简化了它;)

My AsyncComponent.js file
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和分割我的代码之前,我没有这个问题...但是我不明白它来自哪里

Thank you very much for your help

I am using Webpack 3.7.1 and React 15.6.1 and I am loading different components dynamically.

What i did Using AsyncComponent and import() to generate the chunks and load components asynchronously Configured the webpack.config file properly so that the chunks are created (code splitting) The issue The components are rerendered (mounted) multiple times. If I console log something in any of the componentDidMount() of any components, it appears in my console 2 or more times !It was not doing so before : when I was just importing normally the component ... The behaviour before I change to async components The components were loaded correctly and mounted only one time ... My Webpack.config file
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(),
  ]
};
My AppContainer.js file
 /**
 * 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>
    );
  }
}

The component itself is more complicated (doing API calls and there are more routes) but simplified it here for stack purposes ;)

My AsyncComponent.js file
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;
  }

I guess the issue comes from the AsyncComponents/chunks generation as I did not have this issue before using AsyncCOmponents and splitting my code in chunks... But I don't get where it is coming from exactly

Thank you very much for your help
解决方案(由网友Ross Allen提供)

尝试在渲染之外移动HomePage的声明。渲染可以调用任意次数,每个返回的组件看起来都不同于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提供可预测的生命周期。


Try moving the declaration of HomePage outside of render. {mark2} can be called any number of times, and each component that is returned will look different to 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>
    );
  }
}

In general, I advise against doing asynchronous work inside React components. Your rendering layer should be synchronous in order to have a predictable life cycle for your UI.


推荐:想去Google查资料?(你懂的)想建站?想测试?想挂机?想折腾?想要高性价比的服务器?点我!!


关于站长

JMJavaMethod的缩写,苦逼码农一个,一直想有番作为,奈何人老力衰,只能四处膜拜大佬以获得动力。已经从单机、局域网、互联网、混到了移动互联网,未来希望能在AI世界里继续混下去。这辈子有个终极目标:财务自由,心灵自由。

近期公告

一个人苦逼开发多日,网站终于正式上线,求关注!!! 一个人苦逼多日,终于正式上线,求关注!!!

找他  
猜你喜欢
想建站?想测试?
想挂机?想折腾?
想去Google查资料?(你懂的)
想要高性价比的服务器?
搬瓦工VPS - 性价最高的美国便宜VPS主机
友情链接

冀ICP备17016304号 版权所有 © JavaMethod.com All Rights Reserved,Theme by 拼图