I have scripts In my React app that are inserted dynamically later on. The scripts don't load.
In my database there is a field called content
, which contains data that includes html and javascript. There are many records and each record can include multiple scripts in the content
field. So it's not really an option to statically specify each of the script-urls in my React app. The field for a record could for example look like:
<p>Some text and html</p>
<div id="xxx_hype_container">
<script type="text/javascript" charset="utf-8" src="https://example.com/uploads/hype_generated_script.js?499892"></script>
</div>
<div style="display: none;" aria-hidden="true">
<div>Some text.</div>
Etc…
I call on this field in my React app using dangerouslySetInnerHTML
:
render() {
return (
<div data-page="clarifies">
<div className="container">
<div dangerouslySetInnerHTML={{ __html: post.content }} />
... some other data
</div>
</div>
);
}
It correctly loads the data from the database and displays the html from that data. However, the Javascript does not get executed. I think the script doesn't work because it is dynamically inserted later on. How can I make these scripts work/run?
This post suggest a solution for dynamically inserted scripts, but I don't think I can apply this solution because in my case the script/code is inserted from a database (so how to then use nodeScriptReplace
on the code...?). Any suggestions how I might make my scripts work?
Update in response to @lissettdm their answer:
constructor(props) {
this.ref = React.createRef();
}
componentDidUpdate(prevProps, prevState) {
if (prevProps.postData !== this.props.postData) {
this.setState({
loading: false,
post: this.props.postData.data,
//etc
});
setTimeout(() => parseElements());
console.log(this.props.postData.data.content);
// returns html string like: `<div id="hype_container" style="margin: auto; etc.`
const node = document.createRange().createContextualFragment(this.props.postData.data.content);
console.log(JSON.stringify(this.ref));
// returns {"current":null}
console.log(node);
// returns [object DocumentFragment]
this.ref.current.appendChild(node);
// produces error "Cannot read properties of null"
}
}
render() {
const { history } = this.props;
/etc.
return (
{loading ? (
some code
) : (
<div data-page="clarifies">
<div className="container">
<div ref={this.ref}></div>
... some other data
</div>
</div>
);
);
}
The this.ref.current.appendChild(node);
line produces the error:
TypeError: Cannot read properties of null (reading 'appendChild')
If your are sure about HTML string content is safety and contains a string with valid HTML you can use Range.createContextualFragment() (executes scripts )
See how
script
content is executed on JavaScript console working exampleIf your are using
class component
createref
within class constructor, then update node content, I did it incomponentDidMount
just for testing:see this working example