9
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SPAで外部スクリプトを動的にロードする方法

Posted at

何をするか

SPAで外部から読み込むスクリプトのコード<script>~~~</sccript>をページによって切り替えれるかを調べたのでまとめます。

↓このような感じです。
ダウンロード.gif

react-headerでタイトルを変更する要領で動的にロードさせようとしましたが、発火させることができなかったため以下のような方法を取りました。
サイト全体で使う時はグローバルにおけばいいのですが、使用箇所が限定される場合はこのような使い方をしてみてもいいのかもと思います:open_hands:

構成

PageAとPageBがあり、PageBでのみ外部スクリプトを読み込むこととします。
(外部スクリプトはalert.jsというalertを出すだけのjsを用意しました)

.
// htmlにrender
├── index.js
└── modules
       //↓react-routerで出しわけ
    ├── App.js
    | // ↓PageAのコンポーネント(外部スクリプトの読み込み無し)
    ├── PageA.js
    | // ↓PageBのコンポーネント(外部スクリプトの読み込みあり)
    ├── PageB.js
    | // ↓別コンポーネントで読み込んだ外部スクリプトを削除する関数
    ├── clearScript.js
    | // ↓scriptタグを動的に作成する関数
    └── loadDynamicScript.js

App.js

react-routerで出しわけのみを記述しています。

app.js
import React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";

import PageA from "./PageA";
import PageB from "./PageB";

// React-Routerのルーティングのみ
const App = () => {
  return (
    <Router>
      <Switch>
        <Route path="/" exact>
          <PageA />
        </Route>
        <Route path="/B" exact>
          <PageB />
        </Route>
      </Switch>
    </Router>
  );
};

export default App;


PageA.js

PageAのコンポーネント *外部スクリプトの読み込み無し

PageA.js
import React, { useEffect } from "react";
import { BrowserRouter as Router, useHistory } from "react-router-dom";

import { clearScript } from "./clearScript";

// 外部スクリプトの読み込み無し
const PageA = () => {
  const history = useHistory();

  // 別ページで外部スクリプトが読み込まれている場合削除する
  useEffect(() => {
    clearScript();
  }, []);

  return (
    <div>
      <p>this is PageA</p>
      <button onClick={() => history.push("/B")}>Next</button>
    </div>
  );
};

export default PageA;

PageB.js

PageBのコンポーネント *外部スクリプトの読み込みあり
今回はreact-hooksを使いましたが、componentWillMountで呼び出せばOKです!

PageB.js
import React, { useState, useEffect } from "react";
import { BrowserRouter as Router, useHistory } from "react-router-dom";

import { loadDynamicScript } from "./loadDynamicScript";

const PageB = () => {
  const [hasScript, setHasScript] = useState(false);

  // 外部スクリプトを動的に読み込む
  useEffect(() => {
    loadDynamicScript(() => {
      setHasScript(true);
    });
  }, [hasScript]);

  const history = useHistory();
  return (
    <div>
      {/* 外部スクリプトの読み込み完了後に表示 */}
      {hasScript ? (
        <div>
          <p>this is PageB</p>
          <button onClick={() => history.goBack()}>Go Back</button>
        </div>
      ) : (
        ""
      )}
    </div>
  );
};

export default PageB;

clearScript.js

別コンポーネントで読み込んだ外部スクリプトを削除する関数です。
PageAに遷移した場合PageBでappendされたスクリプトタグが残るためそちらを削除します。

clearScript.js
// 作成したscriptタグを削除する
export const clearScript = () => {
  const externalScript = document.getElementsByClassName("externalScript");

  if (externalScript) {
    console.log(externalScript);
    while (externalScript.length) {
      externalScript.item(0).remove();
    }
  }
};

loadDynamicScript.js

外部スクリプト(<script></script>タグ)を動的にを作成し、<body></body>の中に挿入する関数を作成します。

loadDynamicScript.js
export const loadDynamicScript = callback => {
  // スクリプトに付与するIDを指定
  const scriptId = "alert";
  const existingScript = document.getElementById(scriptId);

  // scriptががなければ新しく作成する
  if (!existingScript) {
    const script = document.createElement("script");
    script.id = scriptId;
    script.type = "text/javascript";
    // 外部スクリプトのURLはコチラに
    script.src = "./alert.js";
    // 削除するためのtargetとしてclassNameを付与
    script.className = "externalScript";
    // 作成したtagをappend
    document.body.appendChild(script);

    script.onload = () => {
      if (callback) callback();
    };
  }

  if (existingScript && callback) callback();
};

もっといい方法があるのでは??と思いながら書いていました。。
何か良き方法があればご教示頂きたいです:bow:

参考記事

9
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?