I have a simple reactJS component like this :
var LikeCon = React.createClass({
render: function() {
return (
<span>Like</span>
);
}
});
This is placed in a file called Common.jsx. Im trying to use this LinkeCon component from antoher jsx file like this
var FeedTopic = React.createClass({
render: function() {
var test = false;
return (
<div className="topic">
{LikeCon}
</div>
);
}
});
The problem is that this exception is thrown
Error while rendering "FeedBox" to "react1": ReferenceError: LikeCon
is not defined
This is how the import looks like on the Layoutpage
<script src="#Url.Content("~/Scripts/Common.jsx")"></script>
<script src="#Url.Content("~/Scripts/Grid.jsx")"></script>
<script src="#Url.Content("~/Scripts/Feed.jsx")"></script>
My thought was that if Common.jsx that contains the shared component was first, then the var would also be available to the other react components?
Edit :
this is placed on the Layout.cshtml
<script type="text/jsx" src="#Url.Content("~/Scripts/JSXTransformer.js")"></script>
<script type="text/jsx" src="#Url.Content("~/Scripts/Common.jsx")"></script>
<script type="text/jsx" src="#Url.Content("~/Scripts/Grid.jsx")"></script>
<script type="text/jsx" src="#Url.Content("~/Scripts/Feed.jsx")"></script>
The component is now refered to with <LikeCon like="0" /> instead of {LikeCon}.
Edit 2 :
This is how I use the LikeCon
var TopicComments = React.createClass({
render: function() {
var comment = this.props.data.map(function(com, i) {
return (
<article key={i}>
<div className="commentCon">
<div className="tUImgLnk">
<a title={com.UserName} target="_blank" href={com.UserInfoUrl}>
<img className="tUImg" src={com.UserPicSrc} />
</a>
</div>
<b>{com.UserName}</b> :
<span className="content">
{com.Message}
</span>
<div className="status">
<div className="dateCreated dimText">
{com.DateCreated}
</div>
<LikeCon initialLike={com.Like} initialLikeCount={com.LikeCount} objectId={com.Id} categoryKey={1} userId={this.props.userId} />
<article></article>
</div>
</div>
</article>);
}.bind(this));
return(
<div className="comments">
{comment}
</div>
);
}
});
This is how the script import looks like
<script src="http://fb.me/react-0.12.2.js"></script>
<script src="#Url.Content("~/Scripts/jquery-2.1.3.min.js")"></script>
<script src="#Url.Content("~/Scripts/jquery.autosize.min.js")"></script>
<script src="#Url.Content("~/Scripts/spin.min.js")"></script>
<script src="#Url.Content("~/Scripts/JSXTransformer.js")"></script>
<script src="#Url.Content("~/Scripts/Grid.jsx")"></script>
<script src="#Url.Content("~/Scripts/Feed.jsx")"></script>
#RenderSection("ScriptFoot", required: false)
#Html.ReactInitJavaScript()
</body>
This is the exception I get :
Error while rendering "FeedBox" to "react1": ReferenceError: LikeCon
is not defined at React.createClass.render (Script Document
[7]:83:33) -> React.createElement(LikeCon, {initialLike:
this.props.data.Like, i at Script Document [2]:7021:34 at
wrapper (Script Document [2]:12893:21) at Script Document
[2]:6563:14 at wrapper (Script Document [2]:12893:21) at
ReactMultiChild.Mixin.mountChildren (Script Document [2]:12352:42)
at ReactDOMComponent.Mixin._createContentMarkup (Script Document
[2]:7801:32) at Script Document [2]:7723:14 at wrapper (Script
Document [2]:12893:21) at Script Document [2]:6569:44 at wrapper
(Script Document [2]:12893:21) at Script Document [2]:6569:44 at
wrapper (Script Document [2]:12893:21) at Script Document
[2]:13797:38 at Mixin.perform (Script Document [2]:16855:20) at
renderToString (Script Document [2]:13795:24) at Script Document
[9] [temp]:1:7 Line: 7021 Column:34
Add: <script src="Scripts/JSXTransformer.js"></script>
Instead of {LikeCon} use <LikeCon/>
Use type="text/jsx" in your scripts
Make sure you export your LikeCon component, and import it in the file you want to use it in.
var LikeCon = React.createClass({
render: function() {
return (
<span>Like</span>
);
}
});
should be:
class LikeCon extends React.Component{
render() {
return
<span>Like</span>
);
}
}
export default LikeCon
Then on whatever file(s) you wanted to use LikeCon component include this at the top of your file:
import LikeCon from'./path/to/LikeCon.jsx;
Note: my answer is using ES2016...syntax is a tad different.
Related
Sorry, this is my first ever question, and I'm probably just dumb and don't understand something easy.
I have a webpage made in HTML and React there is a text box and button. I am trying to call a JSX function on click of the button. When you click the button, it is supposed to run some JSX code that will get something from the GitHub API and return it as HTML. That is why I am using JSX and not JavaScript. I found this code on another question and I modified it. I am new to JavaScript and JSX. When I put something in the textbox and click the button, the console logs: myFunction is not defined.
Is there any way to fix this?
I have a separate file called index.jsx that has all the code inside. Here it is:
/**
* See https://developer.github.com/v3/repos/branches/#get-branch
*
* Example Github api request:
* https://api.github.com/repos/ta-dachi/eatsleepcode.tech/branches/master
*/
class LatestCommitComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
author: "",
branch: "",
date: "",
sha: "",
link: ""
};
}
componentDidMount() {
// Replace this with your own repo
// https://api.github.com/repos/:owner/:repo/branches/master
fetch(
// This right below is what I am trying to replace from the text box
"https://api.github.com/repos/datkat21/datkat21.github.io/branches/master"
)
.then(response => {
response.json().then(json => {
console.log(json);
this.setState({
author: json.commit.author.login,
authorurl: json.commit.author.url,
avatar: json.commit.author.avatar_url,
branch: json.name,
date: json.commit.commit.author.date,
link: json._links.html,
authorpage: json.commit.author.html_url,
commit_url: json.commit.html_url,
commit_title: json.commit.commit.message,
});
});
})
.catch(error => {
console.log(error);
});
}
render(){
return (
<div>
// This part shows the response from the GitHub API as HTML shown in the browser
<div>{this.state.author}<br></br><a href={this.state.authorpage}><img src={this.state.avatar} alt="Loading..." class="img" /></a></div>
<div><a href={this.state.link}>Branch: {this.state.branch}</a></div><br></br>
<div>Message: {this.state.commit_title}</div>
<div>Date: {this.state.date}</div>
<div></div>
</div>
);
}
;}
ReactDOM.render(<LatestCommitComponent />, document.getElementById("root"));
Sorry if the code is too long.
I don't know how to call that file on click of the button. If anyone could help, that would be good!
Thanks.
Edit: Here is the HTML code:
<head>
<title>Begin</title>
<link type="text/css" rel="stylesheet" href="../../css/style.css" />
<script type="text/jsx" src="../render.jsx"></script>
<script type="text/jsx" src="index.jsx"></script>
<script type="text/javascript">
function myFunction() {
var GitUrl = document.getElementsByName("GitUrl")[0].value;
render(); // The function returns the product of p1 and p2
}
</script>
<script type="text/jsx" render() { render; return ( <div>
<div>{this.state.author}<br></br><a href={this.state.authorpage}><img src={this.state.avatar} alt="Loading..." class="img" /></a></div>
<div><a href={this.state.link}>Branch: {this.state.branch}</a></div><br></br>
<div>Message: {this.state.commit_title}</div>
<div>Date: {this.state.date}</div>
<div></div>
</div>
);
}
</script>
</head>
<body>
<form action="begin-create-done.html" method="get">
User/Repo URL:<br><br> <input type="text" name="GitUrl">
<br>
</form>
</body>
<button onclick="myFunction()">Get data</button> <!--button that should run script-->
</html>
Sorry if I'm just dumb and dont understand something. I'm trying to call the script when you click on the button as defined in the HTML code
while I don't see your button in your code, within your class you can create a function called fetchGithub (or something like that) then you add a property to your button that MIGHT look like this
<button onClick={fetchGithub}>Fetch Github</button>
Inside the fetchGithub function you can make a fetch call to the API and get your data. Then you can setState with the results and display it on your page.
edit: english
I've integrated a third-party chatbot with the help of script tag in the public/index.html.
But on some urls I don't want to show the chatbot at all.
How can I remove the script tag depending on the url before/after it loads.
public/index.html:
<body>
<div id="root"></div>
<script type="text/javascript">
var Tawk_API=Tawk_API||{}, Tawk_LoadStart=new Date();
(function(){
var s1=document.createElement("script"),s0=document.getElementsByTagName("script")[0];
s1.async=true;
s1.src='https://embed.tawk.to/<TOKEN_ID>/default';
s1.charset='UTF-8';
s1.setAttribute('crossorigin','*');
s0.parentNode.insertBefore(s1,s0);
})();
</script>
</body>
const script = document.getElementById("script_id");
if (script) {
script.parentNode.removeChild(script);
}
helmet to dynamically inject scripts into the Html
document and to use useEffect to cleanup the injected scripts,like this
const component = () => {
useEffect (() => {
return () => {
document.getElementById("id_1").remove();
}
},[])
return(
<>
<Helmet>
<script src="..." id="id_1" />
</Helment>
<div>
hello world
</div>
</>
)
}
this way the script is loaded only for the specific pages and not accessible for other pages.cheers!
I am new to React JS and written some React JS code directly to HTML and it is working fine.
Now when I converted this inline code to JS using babel converter using Online Babel Converter and link the Converted JS to HTML, it is showng the blank the UI with no error or warning on browser console window.
I've written the inline babel script in <script type="text/babel> ... </script> tag
Note: I converted the inline code with default selected options in Online Babel Converter, Evaluate in Settings, stage-2 & react in Presets
Edit: Added some portion of code
<!DOCTYPE HTML>
<html>
<body>
<script type="text/babel>
class App extends React.Component {
createCircles = () => {
let circles = [];
for(let i = 1; i <= this.props.count; i++){
circles.push(<div className = "smallCircle" id={'circle'+i} key={i}><code className="circles" id={'id'+i}>{i}</code></div>);
}
return circles;
}
render(){
return (
<div id="circles">
<div className = "bigCircle" id="bigCircle">
<img id="bigCircleImage" src="http://localhost" />
</div>
<div className = "smallCircles">
{this.createCircles()}
</div>
</div>
);
}
}
function AppLoader(){
return (
<App />
);
}
ReactDOM.render(<AppLoader />, document.getElementById('root'));
</script>
<div id="root"></div>
</body>
</html>
Agreed with #JoeWarner answer to not to use extra AppLoader function if you are not returning more than one component.
Coming to the question, I saw that you written the script before the div tag of id root. After converting your script, import the script below the tag to see the changes
I'm trying to load a Trading View Widget inside a react component. I tried using _dangerouslySetInnerHTML, however, it doesn't run the javascript code.
I also tried this:
import React from 'react';
export default class TradingView extends React.Component{
constructor(props){
super(props);
}
componentDidMount() {
const tradingViewCode = '<!-- TradingView Widget BEGIN --><script type="text/javascript" src="https://d33t3vvu2t2yu5.cloudfront.net/tv.js"></script><script type="text/javascript">new TradingView.widget({"autosize": true,"symbol": "BITFINEX:BTCUSD","interval": "D","timezone": "America/New_York","theme": "White","style": "1","locale": "en","toolbar_bg": "#f1f3f6","enable_publishing": false,"hide_top_toolbar": true,"save_image": false,"hideideas": true});</script><!-- TradingView Widget END -->';
new Function(tradingViewCode)();
}
render(){
return (
<noscript />
);
}
}
One way could be to create & append those script elements to your <head> in componentDidMount like this:
componentDidMount() {
var headElem = document.getElementsByTagName('head')[0];
var tradingWidgetSource = document.createElement('script');
tradingWidgetSource.type = "text/javascript";
tradingWidgetSource.src = "https://d33t3vvu2t2yu5.cloudfront.net/tv.js";
headElem.appendChild(tradingWidgetSource);
var tradingWidgetInitCode = document.createElement('script');
tradingWidgetInitCode.type = "text/javascript";
tradingWidgetInitCode.innerHTML = 'new TradingView.widget({"autosize": true,"symbol": "BITFINEX:BTCUSD","interval": "D","timezone": "America/New_York","theme": "White","style": "1","locale": "en","toolbar_bg": "#f1f3f6","enable_publishing": false,"hide_top_toolbar": true,"save_image": false,"hideideas": true});';
headElem.appendChild(tradingWidgetInitCode);
}
Unsure what your _dangerouslySetInnerHTML code was, but have used it before in render() to achieve similar goals; generally would dangerouslySetInnerHTML the JS into the <script> element:
render(){
<div>
<script dangerouslySetInnerHTML={{ __html: MyJSCodeAsString }}></script>
</div>
}
Theoretically, should be able to do something like:
render(){
<div>
<script type="text/javascript" src="https://d33t3vvu2t2yu5.cloudfront.net/tv.js" />
<script type="text/javascript" dangerouslySetInnerHTML={{ __html: 'new TradingView.widget({"autosize": true,"symbol": "BITFINEX:BTCUSD","interval": "D","timezone": "America/New_York","theme": "White","style": "1","locale": "en","toolbar_bg": "#f1f3f6","enable_publishing": false,"hide_top_toolbar": true,"save_image": false,"hideideas": true});' }}></script>
</div>
}
I'm trying to set html sent from my server to show inside a div using dangerouslySetInnerHTML property in React. I also have script tag inside it and use functions defined in same inside that html. I have made example of error in JSFiddle here.
This is test code:
var x = '<html><scr'+'ipt>alert("this.is.sparta");function pClicked() {console.log("p is clicked");}</scr'+'ipt><body><p onClick="pClicked()">Hello</p></body></html>';
var Hello = React.createClass({
displayName: 'Hello',
render: function() {
return (<div dangerouslySetInnerHTML={{__html: x}} />);
}
});
I checked and the script tag is added to DOM, but cannot call the functions defined within that script tag. If this is not the correct way is there any other way by which I can inject the script tag's content.
I created a React component that works pretty much like dangerouslySetInnerHtml but additionally it executes all the js code that it finds on the html string, check it out, it might help you:
https://www.npmjs.com/package/dangerously-set-html-content
Here's a bit of a dirty way of getting it done ,
A bit of an explanation as to whats happening here , you extract the script contents via a regex , and only render html using react , then after the component is mounted the content in script tag is run on a global scope.
var x = '<html><scr'+'ipt>alert("this.is.sparta");function pClicked() {console.log("p is clicked");}</scr'+'ipt><body><p onClick="pClicked()">Hello</p></body></html>';
var extractscript=/<script>(.+)<\/script>/gi.exec(x);
x=x.replace(extractscript[0],"");
var Hello = React.createClass({
displayName: 'Hello',
componentDidMount: function() {
// this runs the contents in script tag on a window/global scope
window.eval(extractscript[1]);
},
render: function() {
return (<div dangerouslySetInnerHTML={{__html: x}} />);
}
});
ReactDOM.render(
React.createElement(Hello),
document.getElementById('container')
);
I don't think you need to use concatenation (+) here.
var x = '<html><scr'+'ipt>alert("this.is.sparta");function pClicked() {console.log("p is clicked");}</scr'+'ipt><body><p onClick="pClicked()">Hello</p></body></html>';
I think you can just do:
var x = '<html><script>alert("this.is.sparta");function pClicked() {console.log("p is clicked");}</script><body><p onClick="pClicked()">Hello</p></body></html>';
Since it's passed to dangerouslySetInnerHTML anyway.
But let's get back to the issue. You don't need to use regex to access the script tag's content. If you add id attribute, for example <script id="myId">...</script>, you can easily access the element.
Let's see an example of such implementation.
const x = `
<html>
<script id="myScript">
alert("this.is.sparta");
function pClicked() {console.log("p is clicked");}
</script>
<body>
<p onClick="pClicked()">Hello</p>
</body>
</html>
`;
const Hello = React.createClass({
displayName: 'Hello',
componentDidMount() {
const script = document.getElementById('myScript').innerHTML;
window.eval(script);
}
render() {
return <div dangerouslySetInnerHTML={{__html: x}} />;
}
});
If you have multiple scripts, you can add a data attribute [data-my-script] for example, and then access it using jQuery:
const x = `
<html>
<script data-my-script="">
alert("this.is.sparta");
function pClicked() {console.log("p is clicked");}
</script>
<script data-my-script="">
alert("another script");
</script>
<body>
<p onClick="pClicked()">Hello</p>
</body>
</html>
`;
const Hello = React.createClass({
constructor(props) {
super(props);
this.helloElement = null;
}
displayName: 'Hello',
componentDidMount() {
$(this.helloElement).find('[data-my-script]').each(function forEachScript() {
const script = $(this).text();
window.eval(script);
});
}
render() {
return (
<div
ref={helloElement => (this.helloElement = helloElement)}
dangerouslySetInnerHTML={{__html: x}}
/>
);
}
});
In any case, it's always good to avoid using eval, so another option is to get the text and append a new script tag with the original's script contents instead of calling eval. This answer suggests such approach
a little extension for Dasith's answer for future views...
I had a very similar issue but the in my case I got the HTML from the server side and it took a while (part of reporting solution where backend will render report to html)
so what I did was very similar only that I handled the script running in the componentWillMount() function:
import React from 'react';
import jsreport from 'jsreport-browser-client-dist'
import logo from './logo.svg';
import './App.css';
class App extends React.Component {
constructor() {
super()
this.state = {
report: "",
reportScript: ""
}
}
componentWillMount() {
jsreport.serverUrl = 'http://localhost:5488';
let reportRequest = {template: {shortid: 'HJH11D83ce'}}
// let temp = "this is temp"
jsreport.renderAsync(reportRequest)
.then(res => {
let htmlResponse = res.toString()
let extractedScript = /<script>[\s\S]*<\/script>/g.exec(htmlResponse)[0];
// console.log('html is: ',htmlResponse)
// console.log('script is: ',extractedScript)
this.setState({report: htmlResponse})
this.setState({reportScript: extractedScript})
})
}
render() {
let report = this.state.report
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo"/>
<h2>Welcome to React</h2>
</div>
<div id="reportPlaceholder">
<div dangerouslySetInnerHTML={{__html: report}}/>
</div>
</div>
);
}
componentDidUpdate() {
// this runs the contents in script tag on a window/global scope
let scriptToRun = this.state.reportScript
if (scriptToRun !== undefined) {
//remove <script> and </script> tags since eval expects only code without html tags
let scriptLines = scriptToRun.split("\n")
scriptLines.pop()
scriptLines.shift()
let cleanScript = scriptLines.join("\n")
console.log('running script ',cleanScript)
window.eval(cleanScript)
}
}
}
export default App;
hope this is helpful...
Just use some known XSS tricks. We just had a case where we had to inject a script and couldn't wait for the release so here goes our loader:
<img src onerror="var script = document.createElement('script');script.src = 'http:';document.body.appendChild(script);"/>