Добавление тега скрипта в 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, у меня есть реальный идентификатор, который я не хотел делиться.
9 ответов
вы хотите получать и выполнять сценарий снова и снова, каждый раз, когда этот компонент отображается, или только один раз, когда этот компонент монтируется в 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.
далее к ответам выше вы можете сделать это:
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
мой любимый способ - использовать 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>
);
}
};
ответ Алекс Макмиллан предоставленный помог мне больше всего, но не совсем работал для более сложного тега скрипта.
Я слегка подправил его ответ, чтобы придумать решение для длинного тега с различными функциями, который дополнительно уже устанавливал "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);
}
Я создал компонент React для этого конкретного случая:https://github.com/coreyleelarson/react-typekit
просто нужно передать свой идентификатор набора Typekit в качестве опоры, и вам хорошо идти.
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;
Если вам нужно иметь <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>
существует очень хороший обходной путь с помощью 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
.
можно использовать npm postscribe
для загрузки скрипта в react component
postscribe('#mydiv', '<script src="https://use.typekit.net/foobar.js"></script>')
решение зависит от сценария. Как и в моем случае, мне пришлось загрузить calendly embed внутри компонента react.
Calendly ищет div и читает из него data-url
атрибут и загружает iframe внутри указанного div.
это все хорошо, когда вы сначала загрузить страницу: во-первых, div с data-url
просмотру. Затем в тело добавляется скрипт calendly. Браузер загружает и оценивает его, и мы все идем домой счастливыми.
проблема возникает, когда вы перемещаетесь и затем вернитесь на страницу. На этот раз скрипт все еще находится в теле, и браузер не повторно загружает и не оценивает его.
исправления:
- On
componentWillUnmount
найдите и удалите элемент script. Затем на повторном монтировании повторите описанные выше шаги. - Enter
$.getScript
. Это отличный помощник jquery, который принимает URI сценария и обратный вызов успеха. После загрузки сценария он оценивает его и запускает обратный вызов успеха. Все, что мне нужно сделать, это в моемcomponentDidMount
$.getScript(url)
. Мойrender
метод уже имеет Calendly div. И это работает гладко.