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

简介: 大家好,我是海怪。最近发现接手的项目里一直有用 react-hot-loader 这个库,然后我就想:Webpack 不是已经有了一个 HMR(Hot Module Replacement) 的玩意了么?还要这个 loader 干啥的?然后搜到了这篇文章:Blogged Answers: Webpack HMR vs React-Hot-Loader这是一篇关于 HMR 和 react-hot-loader 的对比总结,里面讲得还比较清楚,下面给大家分享一下。

image.png

大家好,我是海怪。

最近发现接手的项目里一直有用 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 组件么?在使用

<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>


相关文章
|
JavaScript 前端开发
VUE组件:如何在Vue中实现组件的动态引入?
VUE组件:如何在Vue中实现组件的动态引入?
2066 0
|
安全 Go 索引
Go切片循环就用range 有这一篇就够了
Go切片循环就用range 有这一篇就够了
694 0
|
11月前
|
传感器 存储 监控
树莓派的应用场景有哪些
树莓派是一种小型、低成本的计算机,广泛应用于教育、家庭自动化、媒体中心、游戏、机器人、物联网项目等领域,支持多种操作系统和编程语言。
1869 8
|
自然语言处理 前端开发 Go
5 大场景上手通义灵码企业知识库 RAG
大家好,我是通义灵码,你的智能编程助手!今天就跟大家分享下企业知识库能帮开发者做些什么。
|
11月前
|
传感器 安全 Java
如何使用 CoAP 协议进行设备通信
CoAP(Constrained Application Protocol)是一种适用于资源受限设备的轻量级协议,常用于物联网(IoT)设备之间的通信。本文介绍如何使用 CoAP 协议进行设备通信,包括协议的基本概念、消息格式、请求与响应流程以及实际应用示例。
1451 3
|
JavaScript
Vue3倒计时(Countdown)
这篇文章介绍了如何在Vue 3中创建一个可自定义的倒计时组件(Countdown),允许设置标题、前缀、后缀、格式和样式,并提供了组件的实现代码和使用示例。
1030 2
Vue3倒计时(Countdown)
|
机器学习/深度学习 JSON 自然语言处理
LLM2Vec介绍和将Llama 3转换为嵌入模型代码示例
通过LLM2Vec,我们可以使用LLM作为文本嵌入模型。但是简单地从llm中提取的嵌入模型往往表现不如常规嵌入模型。
586 5
|
安全 应用服务中间件 网络安全
应用防火墙WAF架构分类
【7月更文挑战第10天】Web Application Firewall (WAF) 是用于保护Web应用的系统,通过HTTP/HTTPS流量规则阻止入侵。
|
SQL 关系型数据库 MySQL
基于proxysql实现MySQL读写分离
基于proxysql实现MySQL读写分离
366 0
|
监控 Shell 调度
Mac创建定时任务
Mac创建定时任务