前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >热更新傻傻分不清:Webapck HMR vs React-Hot-Loader

热更新傻傻分不清:Webapck HMR vs React-Hot-Loader

作者头像
写代码的海怪
发布2022-03-30 08:21:06
4710
发布2022-03-30 08:21:06
举报
文章被收录于专栏:海怪的编程小屋

大家好,我是海怪。

最近发现拉手的项目里一直有用 react-hot-loader 这个库,然后我就想:Webpack 不是已经有了一个 HMR(Hot Module Replacement) 的玩意了么?还要这个 loader 干啥的?

然后搜到了这篇文章:Blogged Answers: Webpack HMR vs React-Hot-Loader

这是一篇关于 HMR 和 react-hot-loader 的对比总结,里面讲得还比较清楚,下面给大家分享一下。

前言

很多人在构建 React 热更新的时候经常被 Webpack 的 HMR 搞蒙逼。一个经常容易把人搞蒙的点就是:以为要用 react-hot-loader 来打开 HMR,然而事实并不是这样,下面我就来对比一下他们的不同点。

HMR

Hot Module Replacement(HMR) 其实是 Webpack 自带的功能,通过 module.hot.accept 来实现。它的原理是:当项目里的文件被重新编译的时候,在 HMR 注册的一回调就会被执行:

  • 除了项目里的入口文件,你要把 HMR client 代码也要作为入口文件。当然,这部分的 client 代码占很小一块,它只是负责打开 WebSocket,并连接上 Webpack dev server
  • 入口调用 module.hot.accept("./someFileName", callbackToRunWhenThatFileIsRecompiled)
  • Webpack dev server 会自动监听文件变化,当保存的时候自动重新编译
  • 重新编译后,发消息通知 client,告诉它哪些文件重新编译了,以及最新版本的代码
  • client 会根据重新编译的文件路径来执行 module.hot.accept()回调函数

关于最后一点的 回调函数 要如何实现完全在于你自己。不过,一般的实现方式都是重新 import 变更的文件,并更换掉变更的代码部分,比如 React 组件、Redux 的 reducer 之类的。

如果你只要用这种 "plain HMR" 的话,只需要写一两行的 module.hot.accept() 就完事了:一个用来更新整个 React 根组件,另一个用来更新根 Reducer 文件。

可以看到,上面并没有使用 react-hot-loader 这个玩意!!只需要 Webpack 就可以实现了。

react-hot-loader

react-hot-loader 也是使用了 Webpack 的 HMR API,但是在实现方式上更复杂和强大!

RHL(react-hot-laoder) 会用一个 "proxy" Component(代理组件)包裹你的组件代码。这些 Proxy Component 会更细粒度地调用 module.hot.accept() API 来抓取每个组件的更新,而不会让这些更新 “冒泡” 到根组件。

同时,这些 Proxy Component 还会拥有自己的状态管理机制,来管理被包裹的真实 React 组件。所以,当你代码改了之后,组件的状态还是会保留下来,而不会重新 “刷新”。

文章总结

RHL 还是挺好的...当它没报错的时候。但是,热更新这样的使用场景有太多的边界 case 了,RHL 也不可能囊括这么多 case,所以在使用的时候也会出现很多问题。

比如更改构建配置就可能使得 RHL 不能正常工作。这也是为什么 Dan Abramov 不再继续去搞 RHL,而是在 Create-React-App 里提供一个更稳定、持续、公开的配置环境作为基线,方便之后实现更“聪明”的热更新机制。

我自己来说还是不推荐使用 RHL,而使用原生的 "plain HMR" 就好了。虽然使用 "plain HMR" 在热更新的时候不会保留原来组件的状态,但是它的工作方式更简单粗暴,没那么多花里胡哨的东西。当然 Redux 也对 "plain HMR" 非常友好的,因为在热更新的时候 Redux 的状态一直都会在那,所以 React 组件在重新渲染的时候还是可以使用上次的 Redux 状态。

我的想法

当然上面这篇文章是 17 年写的,现在 Webpack 已经将 module.hot.accept 内置到配置中了,使用上也不用自己调用 API 了。而且 react-hot-loader 也发展了比较久了,很多问题也解决了不少。

个人觉得如果 react-hot-loader 还是值得一试的,如果没有太多问题的情况下。。实在不行就用原生的 HMR 喽。

不过目前发现 react-router 的 v6.x 版本和 react-hot-loader 不太兼容。刚不是说 react-hot-loader 会包一层 Proxy 组件么?在使用

代码语言:javascript
复制
<Routes>
    <Route></Route>
</Routes>

的时候 Route 被包裹了 Proxy Component,而 v6.x 的 Routes 组件只能允许 Route 作为自己的儿子组件,所以会报:Error: [ProxyFacade] is not a component. All component children of must be a or <React.Fragment>。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 写代码的海怪 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • HMR
  • react-hot-loader
  • 文章总结
  • 我的想法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档