Webpack Hot Module Replacement + React

时间:2018-04-12 14:43:15

标签: reactjs webpack hot-reload

可能这是成千上万的类似问题之一,但我仍然没有看到任何关于如何使HMR 真正工作的答案。

我完成了docs中描述的所有操作,以及您可以通过互联网找到的每个答案:

  • 启用webpack-dev-server的“hot”选项
  • 添加webpack-dev-server/client?{host:port}webpack/hot/only-dev-server入口点
  • new webpack.HotModuleReplacementPlugin()添加到插件(以及NamedModulesPlugin)
  • react-hot-loader
  • 文档中的每一步

现在我拥有了。

假设我的应用看起来像这样:

<ReactRouter>
  <App>
    <AppRouter />
  </App>
</ReactRouter>

AppRouter就像

<Switch>
  <Route path="..." component={Page} />
  ...
</Switch>

Page只是<div>some text<div>

根据文档,在App模块中我做:

import { hot } from "react-hot-loader"
export default hot(module)(App)

然后尝试将Page组件中的文字修改为“新文字”。

在控制台中我看到确实启用了HMR:

[WDS] App hot update...
[HMR] Checking for updates on the server...
[HMR] Updated modules:
[HMR]  - ./Page.js
[HMR]  - ./AppRouter.js
[HMR]  - ./App.js
[HMR] App is up to date.

屏幕上的文字确实更新为“新文字”。到目前为止一切都很好。

然后我再次更新文本到“新文本2”,并看到:

Ignored an update to unaccepted module ./Page.js -> ./AppRouter.js -> ./App.js
[HMR] The following modules couldn't be hot updated: (They would need a full reload!)
[HMR]  - ./Page.js

react-hot-loader文档中有

但是好吧,也许这个文档有些不正确。毕竟,webpack自己的文档明确表明我们应该在代码中执行module.hot.accept(...)

所以在App.js我这样做:

if (module.hot) {
  module.hot.accept("./AppRouter", () => {
    console.log("It works!")
  })
}

然后刷新页面,并尝试再次修改Page组件。

现在控制台说:

[WDS] App hot update...
[HMR] Checking for updates on the server...
App.js:20 It works!
[HMR] Updated modules:
[HMR]  - ./Page.js
[HMR]  - ./AppRouter.js
[HMR]  - ./App.js
[HMR] App is up to date.

但浏览器中的文字未更新。即,HMR已启用但无效。

成功更新说:

[WDS] App hot update...
[HMR] Checking for updates on the server...
[HMR] Updated modules:
[HMR]  - ./Page.js
[HMR] App is up to date.

所以至少我们用unaccepted changes修复了以前的错误 - 但浏览器中仍然没有任何变化。

当App用module.hot.accept(...)修饰时,我尝试hot(module),而当它不是 - 时结果是相同的。

然后......下一步是什么?我做了我能在官方文档中找到的所有内容,但它没有任何效果。我究竟做错了什么?

(请不要问“在我们谈话之前提供你的完整webpack配置”。这都是默认的,相应的例子来自webpack文档。不要浪费我的时间在这上面)

1 个答案:

答案 0 :(得分:0)

当您接受文件时,您必须自己做这些事情(例如交换组件)。那么......像这样:

if (module.hot) {
  module.hot.accept("./AppRouter", () => {
    const NewAppRouter = require('./AppRouter').default;
    const newApp = (
       <ReactRouter>
          <App>
             <NewAppRouter />
          </App>
       </ReactRouter>
    );
    ReactDom.render(newApp, container);
  });
}

此处我在文件更改时收到通知。然后我需要更改的文件并使用新文件重新呈现我的应用程序。当你使用像redux或mobx这样的状态管理库时,这种方法效果最好,因为当你重新渲染应用程序时,你的应用程序的状态不会改变。