it-roy-ru.com

Добавление тега скрипта в 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>

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

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

161
ArrayKnight

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

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

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

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

    document.body.appendChild(script);
}

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

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

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

233
Alex McMillan

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

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, и скрипт внедряется в него.

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

39
sidonaldson

Мой любимый способ - использовать 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

26
Patrice Wrex

Если вам нужно иметь блок <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>
9
scabbiaza

Ответ Алекс Макмиллан при условии, помог мне больше всего, но не совсем работал для более сложного тега сценария.

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

(В моем случае сценарий должен был жить в голове, что также отражено здесь):

  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);
  }
7
jake2620

Я создал компонент 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
Corey Larson

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

/**
 * Like React's 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.

3
Maximilian Hils

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

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

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

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')
0
ben

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

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

return (

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