在之前一篇webpack4的热更新的最后留下了一点思考,传统的前端开发方式套上webpack去实现热更新是很麻烦的,因为html和JavaScript是分离的,创建和销毁JavaScript无法完全控制。在现在前端的开发方式中,html的所有元素都是由JavaScript控制的,那么是否可以很容易的实现热更新呢??
2018-12-20更新
react-hot-loader
最新更新到了4.6.x,提供了一种新的API,官方介绍说可以提供更好的错误管理,
1 | // App.js |
需要特别注意的是,因为这种方式需要使用Object.assign
,如果需要兼容IE11以下的浏览器,需要提供polyfill
,如可以安装core-js
添加import "core-js/fn/object/assign
可以对比下4.6.x
之前的写法1
2
3import { hot } from 'react-hot-loader'
const App = () => <div>Hello World!</div>
export default hot(module)(App)
准备
先来准备两个文件,React入口文件index.js和组件App.js
index.js代码1
2
3
4
5
6
7
8
9
10import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import "./public/style.css";
const wrapper = document.getElementById("root");
ReactDOM.render(
<App />,
wrapper
);
App.js代码,App中的Button组件非关键代码就不贴了1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22import React from "react";
import { Button } from "./components/button";
import "./public/style.css";
let App = (props) => {
return (
<>
<Button
onClick={() => {
console.log(Button.c);
console.log("test arrow function");
}}
value="click me , don't answer you"
/>
<p>看我实现热更新</p>
</>
);
};
export default App;
添加热更新代码
首先按照webpack4的热更新中的步骤完成webpack.config.js的配置。
然后修改上一节中的入口文件为:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import "./public/style.css";
const wrapper = document.getElementById("root");
ReactDOM.render(
<App />,
wrapper
);
// 增加热更新代码
if (module.hot) {
module.hot.accept("./App", () => {
const App = require("./App").default;
ReactDOM.render(
<App />,
wrapper
);
});
}
尝试更新App.js
及其任意组件,体验下舒爽的热更新
使用react-hot-loader
额,为什么还有react-hot-loader
这么个东西,热更新不都已经实现了么,是的,可是并不完美,打开浏览器的控制台Elements
标签,然后去更新App.js
里面的p
标签,你会发现button
也跟着更新了,我没有更新button
啊。。。。
当然如果页面足够简单也就无所谓了,可是如果组件很多,嵌套很深就不美好了,这个时候就要react-hot-loader
登场了,使用很简单,跟着走就行了。
- 首先把
index.js
和App.js
还原为文章最开始的样子 -
1
npm install react-hot-loader
添加
react-hot-loader/babel
到你的.babelrc
1
2
3
4// .babelrc
{
"plugins": ["react-hot-loader/babel"]
}修改App.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27import React from "react";
// 引入loader
import { hot } from "react-hot-loader";
import { Button } from "./components/button";
import "./public/style.css";
let App = (props) => {
return (
<>
<Button
onClick={() => {
console.log(Button.c);
console.log("test arrow function");
}}
value="click me , don't answer you"
/>
<p>看我实现热更新</p>
</>
);
};
// 增加热更新
if (module.hot) {
App = hot(module)(App);
}
export default App;
尝试更新App.js
及其任意组件,体验下舒爽的热更新, 再也不用担心性能了
Redux热更新
通过store.replaceReducer
可以实现对redux的热替,直接上代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import { createStore } from "redux";
import reducer from "./reducer";
// const store = createStore(reducer);
export const configureStore = () => {
const store = createStore(reducer);
if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept("./reducer", () => {
const nextRootReducer = require("./reducer").default;
store.replaceReducer(nextRootReducer);
});
}
return store;
};
需要注意的是createStore
不要放在App.js
中,避免React组件的更新影响到store
,放到index.js
中就可以了1
2
3
4
5
6
7
8
9
10
11
12import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { configureStore } from "./redux/store";
const store = configureStore();
const wrapper = document.getElementById("root");
ReactDOM.render(
<App store={store}/>,
wrapper
);
更新App.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28import React from "react";
// 引入loader
import { hot } from "react-hot-loader";
import { Button } from "./components/button";
import "./public/style.css";
// 引入Provider
import { Provider } from "react-redux";
let App = (props) => {
return (
<Provider store={props.store}>
<Button
onClick={() => {
console.log(Button.c);
console.log("test arrow function");
}}
value="click me , don't answer you"
/>
<p>看我实现热更新</p>
</Provider>
);
};
// 增加热更新
if (module.hot) {
App = hot(module)(App);
}
export default App;
修改 reducer 也可以实现热更新了
总结
终于可以愉快的玩耍了!!