热更新傻傻分不清: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>


相关文章
|
4月前
|
数据采集 前端开发 JavaScript
我是如何使用 Next.js14 + Tailwindcss 重构个人项目的
这篇文章介绍了作者在学习React和Nest时受到大佬imsyy项目DailyHot的启发,基于React开发了一个项目,并因为这个项目获得了少量流量而进行了优化。作者随后因为想要优化SEO和深入学习Next.js14,决定重构这个项目。文章详细介绍了项目的信息、特性、演示图、运行环境、Vercel本地部署步骤以及责任声明。作者还感谢了为本项目提供支持与灵感的项目,并承诺会记录下开发过程中遇到的问题及解决方法以帮助他人。
我是如何使用 Next.js14 + Tailwindcss 重构个人项目的
|
1月前
|
资源调度 JavaScript 前端开发
|
3月前
|
前端开发
react怎么做图片报错处理
react怎么做图片报错处理
53 1
|
人工智能 前端开发 JavaScript
前端Vue框架在PostCSS怎样使用sass
为什么要使用PostCss 众所周知转换 px 单位的插件有很多,知名的有 postcss-px-to-viewport 和 postcss-pxtorem,前者是将 px 转成 vw,后者是将 px 转成 rem,精简了不常用的配置。将成为vw优先单位使用,以rem作为回退模式。考虑到vw在移动设备的支持度不如rem,这款插件很好的解决了该问题。然后简单的介绍下。
91 0
|
4月前
elementPlus引入
elementPlus引入
90 1
|
4月前
|
资源调度 前端开发 JavaScript
vue - ES6模块化、promise、webpack打包(所在在学的朋友们先看这篇,看了不吃亏)...
vue - ES6模块化、promise、webpack打包(所在在学的朋友们先看这篇,看了不吃亏)...
|
前端开发 索引
【React工作记录七十九】React+hook+ts+ant design封装一个具有动态表格得页面
【React工作记录七十九】React+hook+ts+ant design封装一个具有动态表格得页面
135 0
|
JavaScript 前端开发
学习Vue3 第二十五章(TSX)
vue2 的时候就已经支持jsx写法,只不过不是很友好,随着vue3对typescript的支持度,tsx写法越来越被接受
168 0
学习Vue3 第二十五章(TSX)
|
前端开发
#yyds干货盘点 【React工作记录三十一】dva.js初识
#yyds干货盘点 【React工作记录三十一】dva.js初识
90 0
#yyds干货盘点 【React工作记录三十一】dva.js初识
学习Vue3 第十八章(异步组件&代码分包&suspense)
在大型应用中,我们可能需要将应用分割成小一些的代码块 并且减少主包的体积
94 0