webpackerのサンプルをparcelでつかったらautoloadが効かなかった

はじめに

parcelを使っていて動かすコードとしてwebpackerのreactのサンプルを使っていました。

その中で、parcelにはdefaultでautoloadの機能が備わっているのにloadされないという状態が起こりました。

ここでは原因とその対処法について書いていきます。

問題のコード

https://github.com/rails/webpacker/blob/05062bd72a6e759d34ed3f4e05639dbd0f3b4ce4/lib/install/examples/react/hello_react.jsx

import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'

const Hello = props => (
  <div>Hello {props.name}!</div>
)

Hello.defaultProps = {
  name: 'David'
}

Hello.propTypes = {
  name: PropTypes.string
}

document.addEventListener('DOMContentLoaded', () => {
  ReactDOM.render(
    <Hello name="React" />,
    document.body.appendChild(document.createElement('div')),
  )
})

原因

以下のコードが問題でした。

document.addEventListener('DOMContentLoaded', () => {
  ReactDOM.render(
    <Hello name="React" />,
    document.body.appendChild(document.createElement('div')),
  )
})

autoloadはjsが再実行されるだけなので、addEventListenerで再度イベント登録しても、domがrenderされることはありません。

対処

まず、addEventListenerを使わずReactDOM.renderを即時実行するようにします。そうするとautoloadするたびにappendChildされるので、getElementByIdにして何個もdomが作られないようにします。html側にid要素をもつdivを一個作っておきました。

const mountNode = document.getElementById("app");
ReactDOM.render(<Hello name="React" />, mountNode);

jsのscriptタグがheadに書いてあったので、bodyの一番最後に変更してdivがある状態で読み込まれるようにもしました。

背景

Railsは基本scriptタグはheadに置くので、haedにおいても大丈夫なようにaddEventListenerを使った書き方になっているのだと思います。

まとめ

まだまだjsについては無知だなと感じました。