【React入門13】WDSのHot Module Replacementを使ってみる
こちらの記事は、React入門チュートリアルです。
Reactが初めての私がReactを実装していく流れとなるため、初心者の方のつまずきやすいポイントを一通りフォローアップできる内容となっています。
Hot Module Replacementの有効化
編集されたコードのモジュールのみを更新するHot Module Replacementを使用するためには、webpack.config.jsにコードを記述しなければいけません。
const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const webpack = require('webpack'); //追記 module.exports = { // watchモードを消しておく、またはfalseにしておく watch: false, mode: 'development', entry: './src/index', output: { path: path.resolve(__dirname, 'public'), filename: 'bundle.js' }, module: { rules: [ { test: /\.txt$/, use: 'raw-loader' }, { test: /\.m?js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } } ] }, plugins: [ // プラグインの設定追加 new HtmlWebpackPlugin({ title: 'Plugin generate page', template: 'src/root.html' }), new webpack.HotModuleReplacementPlugin() //追記 ], //以下を追記 devServer: { contentBase: path.join(__dirname, 'public'), port: 9000, hot: true } };
次に以下の2つのファイルを記述しましょう。
src/index.js
function component() { const element = document.createElement('div'); const btn = document.createElement('button'); const myAlert = require('./components/myAlert').default; btn.innerHTML = 'Click me'; btn.onclick = myAlert; element.appendChild(btn); return element; } let element = component(); document.body.appendChild(element); if (module.hot) { module.hot.accept('./components/myAlert.js', () => { document.body.removeChild(element); element = component(); document.body.appendChild(element); }) }
src/components/myAlert.js(新規ファイル)
export default function myAlert() { alert('bar'); }
myAlert.jsを編集した後に更新を行なっていなくても、Alertのメッセージが変わっていることがわかります。
解説をしていきます。
function component() { const element = document.createElement('div'); const btn = document.createElement('button'); const myAlert = require('./components/myAlert').default; btn.innerHTML = 'Click me'; btn.onclick = myAlert; element.appendChild(btn); return element; }
まずこちらのコードで、実行されるとdiv要素とbtn要素が描画される関数を定義しています。
let element = component(); document.body.appendChild(element);
そして、実際にcomponent関数を実行。
これで画面表示がなされるはずです。
if (module.hot) { module.hot.accept('./components/myAlert.js', () => { document.body.removeChild(element); element = component(); document.body.appendChild(element); }) }
最後に「もしモジュールにHot Module Replacementが適用されたら」という条件で、
- divとbtn要素を描画するelementを排除し、
- 新たなelement要素を追加する
といった処理を行わせます。
結果として、myAlert.jsの中身が変わっても、ホットリロードされるというわけです。
ReactにおけるHot Module Replacement
Reactはアトミックデザイン、コンポーネントベースを取り入れたFWのため、webpackのwatchモードといったように「アプリ全体がリロードされてしまう」と困ることが多いようです。
例えば、タブ選択ができるようなアプリを開発している時に、「タブ2」の画面を見ながら開発を続けたくても、全体がリロードされてしまうとコードが編集されるたびにデフォルトタブに戻ってしまうわけです。
Hot Module Replacementは先ほども述べたように、編集されたファイルのみを更新してくれるため、画面全体が再描画されることはありません。
ReactにおけるHot Module Replacementを体験してみる
では実際にReactにおけるHot Module Replacementを体験してみましょう。
src/index.js
import React, { Component } from 'react'; import { render } from 'react-dom'; import Hello from './components/hello'; class App extends Component { constructor() { super(); this.handleChange = this.handleChange.bind(this); this.state = { flag: false } } handleChange() { this.setState({ flag: !this.state.flag }) } render() { return ( <div> <button onClick={this.handleChange}>Switch Flag</button> {`${this.state.flag}`} <Hello/> </div> ) } } render( <App />, document.querySelector('#root') );
src/components/hello.js
import React from 'react'; const Hello = (props) => { return <div>not reloaded!</div> } export default Hello;
これで画面上にはボタンの横にfalseと表示され、その下には「non reloaded!」と書かれているはずです。
ボタンを押してみましょう。
下の「non reloaded!」は再描画されていないことがわかります。
これがReactにおけるHot Module Replacementの利点です。
また、Reactではreact-hot-loaderというプラグインが提供されているので、Reactのアプリケーション作成時に簡単に導入することができます。
github.com