Добавление тега сценария для 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 Kit ID в качестве опоры, и вы хорошо идти.
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
библиотека. Код в реагировать будет: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
чтобы загрузить скрипт в компоненте reactpostscribe('#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
найти и удалить элемент сценария. Затем на повторном монтаже повторите описанные выше шаги.- введите
$.getScript
. Это отличный помощник jquery, который принимает URI сценария и обратный вызов успеха. После загрузки скрипта он оценивает его и запускает обратный вызов успеха. Все, что мне нужно сделать, это в моемcomponentDidMount
$.getScript(url)
. Мойrender
метод уже имеет calendly div. И это работает гладко.