Подтвердить что ты не робот

Добавление тега script в React/JSX

У меня есть относительно простая проблема с попыткой добавить встроенные скрипты к компоненту React. Что я до сих пор:

'use strict';

import '../../styles/pages/people.scss';

import React, { Component } from 'react';
import DocumentTitle from 'react-document-title';

import { prefix } from '../../core/util';

export default class extends Component {
    render() {
        return (
            <DocumentTitle title="People">
                <article className={[prefix('people'), prefix('people', 'index')].join(' ')}>
                    <h1 className="tk-brandon-grotesque">People</h1>

                    <script src="https://use.typekit.net/foobar.js"></script>
                    <script dangerouslySetInnerHTML={{__html: 'try{Typekit.load({ async: true });}catch(e){}'}}></script>
                </article>
            </DocumentTitle>
        );
    }
};

Я также пробовал:

<script src="https://use.typekit.net/foobar.js"></script>
<script>try{Typekit.load({ async: true });}catch(e){}</script>

Ни один из подходов не выполняет желаемый script. Я предполагаю, что это простая вещь, которую мне не хватает. Кто-нибудь может помочь?

PS: Игнорируйте foobar, у меня есть реальный идентификатор, который мне действительно не нравится.

4b9b3361

Ответ 1

Вы хотите снова и снова извлекать и выполнять скрипт, каждый раз, когда этот компонент отображается, или только один раз, когда этот компонент монтируется в DOM?

Возможно, попробуйте что-то вроде этого:

componentDidMount () {
    const script = document.createElement("script");

    script.src = "https://use.typekit.net/foobar.js";
    script.async = true;

    document.body.appendChild(script);
}

Однако, это действительно полезно, только если скрипт, который вы хотите загрузить, не доступен как модуль/пакет. Во-первых, я бы всегда:

  • Ищите пакет на нпм
  • Загрузите и установите пакет в моем проекте (npm install typekit)
  • import пакет, где он мне нужен (import Typekit from 'typekit';)

Вероятно, именно так вы установили пакеты react и react-document-title из своего примера, и есть пакет Typekit, доступный на npm.

Обновление:

Теперь, когда у нас есть хуки, лучшим подходом может стать использование useEffect следующим образом:

useEffect(() => {
  const script = document.createElement('script');

  script.src = "https://use.typekit.net/foobar.js";
  script.async = true;

  document.body.appendChild(script);

  return () => {
    document.body.removeChild(script);
  }
}, []);

Что делает его отличным кандидатом на пользовательский хук (например: hooks/useScript.js):

import { useEffect } from 'react';

const useScript = url => {
  useEffect(() => {
    const script = document.createElement('script');

    script.src = url;
    script.async = true;

    document.body.appendChild(script);

    return () => {
      document.body.removeChild(script);
    }
  }, [url]);
};

export default useScript;

Что можно использовать так:

import useScript from 'hooks/useScript';

const MyComponent = props => {
  useScript('https://use.typekit.net/foobar.js');

  // rest of your component
}

Ответ 2

В дополнение к приведенным выше ответам вы можете сделать это:

import React from 'react';

export default class Test extends React.Component {
  constructor(props) {
    super(props);
  }

  componentDidMount() {
    const s = document.createElement('script');
    s.type = 'text/javascript';
    s.async = true;
    s.innerHTML = "document.write('This is output by document.write()!')";
    this.instance.appendChild(s);
  }

  render() {
    return <div ref={el => (this.instance = el)} />;
  }
}

Div привязан к this, и в него вводится script.

Демо можно найти на codesandbox.io

Ответ 3

Мой любимый способ - использовать React Helmet - это компонент, который позволяет легко манипулировать головкой документа так, как вы, вероятно, уже привыкли.

например

import React from "react";
import {Helmet} from "react-helmet";

class Application extends React.Component {
  render () {
    return (
        <div className="application">
            <Helmet>
                <script src="https://use.typekit.net/foobar.js"></script>
                <script>try{Typekit.load({ async: true });}catch(e){}</script>
            </Helmet>
            ...
        </div>
    );
  }
};

https://github.com/nfl/react-helmet

Ответ 4

Ответ Alex Mcmillan помог мне больше всего, но не совсем работал над более сложным тегом script.

Я слегка подправил свой ответ, чтобы придумать решение для длинного тега с различными функциями, которые дополнительно устанавливали "src".

(Для моего случая использования script необходимо было жить в голове, что также отражено здесь):

  componentWillMount () {
      const script = document.createElement("script");

      const scriptText = document.createTextNode("complex script with functions i.e. everything that would go inside the script tags");

      script.appendChild(scriptText);
      document.head.appendChild(script);
  }

Ответ 5

Если вам нужно иметь блок <script> в SSR (рендеринг на стороне сервера), подход с componentDidMount не будет работать.

Вместо этого вы можете использовать react-safe библиотеку. Код в React будет:

import Safe from "react-safe"

// in render 
<Safe.script src="https://use.typekit.net/foobar.js"></Safe.script>
<Safe.script>{
  'try{Typekit.load({ async: true });}catch(e){}'
}
</Safe.script>

Ответ 6

Я создал компонент React для этого конкретного случая: https://github.com/coreyleelarson/react-typekit

Просто нужно передать свой ID Kitkit Kit в качестве реквизита, и все готово.

import React from 'react';
import Typekit from 'react-typekit';

const HtmlLayout = () => (
  <html>
    <body>
      <h1>My Example React Component</h1>
      <Typekit kitId="abc123" />
    </body>
  </html>
);

export default HtmlLayout;

Ответ 7

Существует очень хороший обходной путь с использованием Range.createContextualFragment.

/**
 * Like React dangerouslySetInnerHTML, but also with JS evaluation.
 * Usage:
 *   <div ref={setDangerousHtml.bind(null, html)}/>
 */
function setDangerousHtml(html, el) {
    if(el === null) return;
    const range = document.createRange();
    range.selectNodeContents(el);
    range.deleteContents();
    el.appendChild(range.createContextualFragment(html));
}

Это работает для произвольного HTML, а также сохраняет контекстную информацию, такую как document.currentScript.

Ответ 8

Вы можете использовать npm postscribe для загрузки скрипта в компонент реагирования

postscribe('#mydiv', '<script src="https://use.typekit.net/foobar.js"></script>')

Ответ 9

Я получил document "undefined" при обновлении. Я попробовал вот так

const MyComponent = () => {
   let script = React.createElement("script", {
    src: "https://.....js path",
    async: true,
    defer: true,
    crossorigin: "anonymous"
})

return (

        <div>
            {script}
        </div>)
}

Ответ 10

для нескольких сценариев используйте это

var loadScript = function(src) {
  var tag = document.createElement('script');
  tag.async = false;
  tag.src = src;
  document.getElementsByTagName('body').appendChild(tag);
}
loadScript('//cdnjs.com/some/library.js')
loadScript('//cdnjs.com/some/other/library.js')

Ответ 11

Перепробовал все предложенные решения, но ни одно из них не сработало. Я пытаюсь встроить это в компонент, но он не загружается. это баннер от bannernack.com.

<script type="text/javascript">
var bannersnack_embed = {"hash":"bxpien9pr","width":1190,"height":300,"t":1559889975,"userId":39254375,"responsive":true,"type":"html5"};
</script>
<script type="text/javascript" src="//cdn.bannersnack.com/iframe/embed.js"></script>

Ответ 12

componentDidMount() {
  const head = document.querySelector("head");
  const script = document.createElement("script");
  script.setAttribute(
    "src",
    "https://assets.calendly.com/assets/external/widget.js"
  );
  head.appendChild(script);
}

Ответ 13

Лучший ответ вы найдете по следующей ссылке:

https://cleverbeagle.com/blog/articles/tutorial-how-to-load-third-party-scripts-dynamically-in-javascript

const loadDynamicScript = (callback) => {
const existingScript = document.getElementById('scriptId');

if (!existingScript) {
    const script = document.createElement('script');
    script.src = 'url'; // URL for the third-party library being loaded.
    script.id = 'libraryName'; // e.g., googleMaps or stripe
    document.body.appendChild(script);

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

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

Ответ 14

Решение зависит от сценария. Как и в моем случае, мне пришлось загрузить календарно встраивание внутри реагирующего компонента.

Календно ищет div и читает из него атрибут data-url и загружает iframe внутри указанного div.

Хорошо, когда вы сначала загружаете страницу: сначала отображается div с data-url. Затем календарно script добавляется к телу. Браузер загружает и оценивает его, и мы все счастливы домой.

Проблема возникает, когда вы перемещаетесь, а затем возвращаетесь на страницу. На этот раз script все еще находится в теле, и браузер не перезагружает и не переоценивает его.

Fix:

  • В componentWillUnmount найдите и удалите элемент script. Затем на re mount повторите описанные выше шаги.
  • Введите $.getScript. Это отличный помощник jQuery, который принимает URI script и успешный обратный вызов. После загрузки script он оценивает его и запускает ваш обратный вызов. Все, что мне нужно сделать, это мой componentDidMount $.getScript(url). У моего метода render уже есть calendly div. И он работает плавно.