今天我们来聊一聊react的模块热更新,熟悉react的同学都知道,使用官方的脚手架,当我们改动页面时,整个页面会被刷新,那我们当然希望页面只刷新我们改动的部分而不是刷新整个页面,那么怎么做到如此呢?千呼万唤始出来,react-hot-loader就是来完成这个伟大的使命的。
npm i react-hot-loader --save
entry: [
isEnvDevelopment && 'react-hot-loader/patch',
// Include an alternative client for WebpackDevServer. A client's job is to
// connect to WebpackDevServer by a socket and get notified about changes.
// When you save a file, the client will either apply hot updates (in case
// of CSS changes), or refresh the page (in case of JS changes). When you
// make a syntax error, this client will display a syntax error overlay.
// Note: instead of the default WebpackDevServer client, we use a custom one
// to bring better experience for Create React App users. You can replace
// the line below with these two lines if you prefer the stock client:
// require.resolve('webpack-dev-server/client') + '?/',
// require.resolve('webpack/hot/dev-server'),
isEnvDevelopment &&
require.resolve('react-dev-utils/webpackHotDevClient'),
// Finally, this is your app's code:
paths.appIndexJs,
// We include the app code last so that if there is a runtime error during
// initialization, it doesn't blow up the WebpackDevServer client, and
// changing JS code would still trigger a refresh.
].filter(Boolean),
如上,entry的第一行即为我们添加的内容。
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
customize: require.resolve(
'babel-preset-react-app/webpack-overrides'
),
plugins: [
isEnvDevelopment && 'react-hot-loader/babel',
[
require.resolve('babel-plugin-named-asset-import'),
{
loaderMap: {
svg: {
ReactComponent: '@svgr/webpack?-svgo,+ref![path]',
},
},
},
],
],
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/
// directory for faster rebuilds.
cacheDirectory: true,
cacheCompression: isEnvProduction,
compact: isEnvProduction,
},
},
如上,plugins配置的第一行:isEnvDevelopment && 'react-hot-loader/babel',即为我们添加的代码,如果配置在.babelrc文件中,则写在.babelrc的plugins配置中。
一般情况下,脚手架初始化的项目此步骤已经满足,无需再改动。
plugins: [
...
new webpack.HotModuleReplacementPlugin(), //设置这里
...
]
一般情况下,脚手架初始化的项目此步骤已经满足,无需再改动。
devServer: {
...
hot: true, //设置这里
...
},
首先,从 react-hot-loader 导入 AppContainer 组件:
import { AppContainer } from 'react-hot-loader';
然后,改写 render 方法:
原 render 为:
ReactDOM.render(
,
document.getElementById('root')
);
修改之后为:
const render = Component => {
ReactDOM.render(
,
document.getElementById('root'));
}
然后,执行render函数,继而再写模块热更新时的处理代码:
render(App);
if (module.hot) {
module.hot.accept('./App', () => {
//因为在App里使用的是export default语法,这里使用的是require,默认不会加载default的,所以需要手动加上
const NextApp = require('./App').default;
// 重新渲染到 document 里面
render(NextApp);
})
}
完整的主入口文件为:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from '@/store';
import * as serviceWorker from './serviceWorker';
import { AppContainer } from 'react-hot-loader';
const render = Component => {
ReactDOM.render(
,
document.getElementById('root'));
}
render(App);
if (module.hot) {
module.hot.accept('./App', () => {
//因为在App里使用的是export default语法,这里使用的是require,默认不会加载default的,所以需要手动加上
const NextApp = require('./App').default;
// 重新渲染到 document 里面
render(NextApp);
})
}
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
至此,我们就已经配置完成了react项目的模块热更新,即局部刷新而不是整个页面的刷新,如此可大大提高开发效率。