React プロジェクトの src 内のコンポーネントから諸事情によりウェブサイト外部の SCRIPT を読む方法のメモ
諸事情の例
- コンポーネントの render 時に CDN やどこかしらから
<script src="https://example.com/hogehoge.js" crossorigin></script>
とかしたい - コンポーネントの render 時に .jsx/.tsx の翻訳時には有効ではない ECMAScript コードをちょろまかしたい
4つの方法
もっとあるというのはさておき。
1. react-script-tag
この方法では DOM 構造的には in-situ な感じで <script>
がぶちこまれます。
準備:
# .jsx 向けしか存在しないので .tsx では @ts-ignore して使います yarn add react-script-tag
実用:
import React, { Component } from "react"; // note: ↓ .tsx ならこのコメントディレクティブを付けないとエラーになります。 .jsx なら不要です // @ts-ignore import ScriptTag from "react-script-tag"; export default class MyAwesomeMainCanvas extends Component { render() { return ( <div> <canvas id="main-canvas"></canvas> <ScriptTag src="runner.main-canvas.something.js" /> </div> ); } }
2. react-helmet
この方法では DOM 構造的には <head>
へ <script>
(というか実際には任意の何かしら、 <title>
とか <link>
でも) をぶちこみます。
注意:
- この方法を採用すると依存ライブラリーの都合か strict mode で警告↓がでて不穏になります。
<script>
用途だけが目的の場合は他の方法がよいかもしれません。 ( Issue -> https://github.com/nfl/react-helmet/issues/426 )- おまけ情報:
react-helmet
の代わりに<script>
をreact-script-tag
へ変更する際に<title>
についても代替が必要な場合は react-document-title & @types/react-document-title が便利です。
- おまけ情報:
index.js:1 Warning: Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. See https://fb.me/react-unsafe-component-lifecycles for details. * Move code with side effects to componentDidMount, and set initial state in the constructor. Please update the following components: SideEffect(NullComponent)
準備:
# for .jsx yarn add react-helmet # for .tsx; 両方必要になります yarn add react-helmet @types/react-helmet
実用:
import React, { Component } from "react"; // for .jsx & .tsx import { Helmet } from "react-helmet"; export default class MyAwesomeMainCanvas extends Component { render() { return ( <div> <canvas id="main-canvas"></canvas> <Helmet> <script src="runner.main-canvas.something.js"></script> <title>にゃーん/title> </Helmet> </div> ); } }
3. DOM 操作でぶちこむ
いわゆるごりごり手書きした的な方法。
import React, { Component } from "react"; export default class MyAwesomeMainCanvas extends Component { render() { return ( <div> <canvas id="main-canvas"></canvas> </div> ); } componentDidMount() { const s = document.createElement( "script" ); s.src = "runner.main-canvas.something.js"; s.async = true; document.body.appendChild( s ); } }
複数箇所で使用したいとか再利用性が欲しい場合は方法(1),(2)を選択するほかか、この方法(3)も手書きオレオレコンポーネント化する方法もあります。コンポーネント化の方法はこのメモの本論ではないので省略。
4. React の Effect Hook 機能
方法(3) のごりごり手書きを若干変態気味に実装する亜種のような方法です。
カスタム・フックを作って:
import { useEffect } from 'react'; export default const myHook = (src) => { useEffect( () => { const s = document.createElement( "script" ); s.src = src; s.async = true; document.body.appendChild( s ); return () => { document.body.removeChild( s ); }; } , [src] ); };
カスタム・フックをひっかける:
// for .jsx // import myHook from 'myHook.jsx'; // for .tsx import myHook from 'myHook'; const Demo = props => { importScript("runner.main-canvas.something.js"); }