I want to have an API with returns HTML with JSX. When the HTML is loaded, I want to convert this to JSX and pass the props from my
Given this set of code:
import { renderToString } from "react-dom/server";
import ReactDOM from 'react-dom';
function MyHtml (props) {
var apiHtml = renderToString("<div>{this.props.title}</div>");
return (
<div dangerouslySetInnerHTML={{ __html: apiHtml }} />
)
}
export default MyHtml;
ReactDOM.render(
<MyHtml title="test"/>,
document.getElementById('test')
);
I want to have the output
<div>test</div>
Instead, I get
<div>{this.props.title}</div>
Thanks
I think what you're looking for is:
var apiHtml = renderToString(`<div>{${this.props.title}}</div>`);
Using template literals to fill in the code you want.
I ended up doing something like this:
var { title } = this.props; // => testing
var html = ReactDOMServer.renderToString("<div>${title}</div>");
var toRender = eval('`'+html +'`');
To give the output:
<div>testing</div>
Thanks everyone!
Related
I have a problem using "setInterval" within React. If I don't use "setInterval", there's no problem, but when I use it, my images won't appeear on my page.Please help.
Here is my component where I've imported the JS file containing the images:
import React from 'react';
import ReactDOM from 'react-dom';
import logo from './lastricouri.jpg';
import img from './app.js';
import inter from './app.js';
class Logo extends React.Component {
render() {
return (
<div id = 'header-container'>
<img src ={logo} id='tricouri'></img>
<img src={inter}></img>
<div id='btns'>
<a href='#' id='logi'>Log In</a>
<a href='#' id='signup'>Sign Up</a>
</div>
<input type='text' id='txt' placeholder='Ai libertatea de a alege!'></input>
</div>
);
}
}
export default Logo;
And here is my component that contains the images:
import first from './1.jpg';
import second from './2.jpg';
import third from './3.jpg';
import fourth from './4.jpg';
import fifth from './5.jpg';
let inter = setInterval(() => {
const tshirts = [first,second,third,fourth,fifth];
const rndimg = Math.floor(Math.random() * 5);
const img = tshirts[rndimg];
},3000);
export default inter;
SetInterval returns a unique interval id which is being assigned to the inter variable. inter does not contain your image source. If you want to assign a random image change your code like this
let inter;
setInterval(() => {
const tshirts = [first,second,third,fourth,fifth];
const rndimg = Math.floor(Math.random() * 5);
inter = tshirts[rndimg];
},3000);
export default inter;
I have some html (JSX) in my react app that looks like this:
<div><h3>Title</h3><p> some message...</p></div>
I am then assigning this to a variable called msg using innerHTML like so:
let msg
msg.innerHTML = "<div><h3>Title</h3><p> some message...</p></div>"
//then i append it to my app like this
document.body.appendChild(msg)
Now i would like to surround the html above with a native React Link element like so
msg.innerHTML = "<Link to"/"><div><h3>Title</h3><p> some message...</p></div></Link>"
of course it doesn't work and it is compiled as regular html when it is rendered to the page as and doesn't act as a react link
How can i achieve this, is it even possible or is there a totally different way of approaching this issue?
I tried doing this and many different variations but to no cigar:
msg.innerHTML = `${<Link to"/">}<div><h3>Title</h3><p> some message...</p></div>${</Link}`
There is ReactDOMServer.renderToString that will render a React element to its initial HTML.
...
import ReactDOMServer from "react-dom/server";
export default function App() {
useEffect(() => {
const msg = document.createElement("div");
msg.innerHTML = ReactDOMServer.renderToString(
<Link to="/">
<div>
<h3>Title</h3>
<p> some message...</p>
</div>
</Link>
);
document.body.appendChild(msg);
}, []);
return null;
}
I am trying to make a react component library so I can use them through out my entire application. I have the first part of the library being a table and this is still in the testing stages but I cannot figure out how to call the component and create it on the page its called. Currently this is how its working. I also just starting programming in React yesterday.
HTML
<script type="text/babel" src="/js/reactcomponents/table.js"></script>
<div id="loadboardContainer">
<div class="table-desc">Future Loads</div>
<div id="futureLoadsContainer"></div>
<div class="table-desc">Todays Loads</div>
<div id ="todaysLoadsContainer"></div>
<div class="table-desc">Active Loads</div>
<div id ="activeLoadsContainer"></div>
</div>
Then I have my react component.
var Table = React.createClass({
getInitialState: function() {
return {
results: [],
columns: []
}
},
componentDidMount: function() {
this.serverRequest = $.get(this.props.source, function(result) {
result = JSON.parse(result);
if(result['resultRows'] == undefined){
result['resultRows'] = [];
}
this.setState({
results: result['resultRows'],
columns: $.makeArray(result['resultCols'])
});
}.bind(this));
},
componentWillUnmount: function(){
this.serverRequest.abort();
},
render: function() {
// Set array for rows.
var rows = [];
var header = [];
this.state.columns.map(function(cols) {
header.push(<TableColumns data={cols.cols} key={cols.id} />);
});
this.state.results.map(function(result) {
rows.push(<TableRow data={result.rows} key={result.id} />);
});
// Return the table.
return (
<table className="table table-condensed table-bordered no-bottom-margin">
<thead>
{header}
</thead>
<tbody>
{rows}
</tbody>
</table>
);
}
});
// Set up columns
var TableColumns = React.createClass({
render: function() {
var colNodes = this.props.data.map(function(col, i){
return (
<th key={i}>{col}</th>
);
});
return (
<tr>
{colNodes}
</tr>
);
}
});
// Set up row
var TableRow = React.createClass({
render: function() {
var rowNodes = this.props.data.map(function(row, i){
return (
<td key={i}>{row}</td>
);
});
return (
<tr>
{rowNodes}
</tr>
);
}
});
var futureContainer = document.getElementById('futureLoadsContainer');
var todaysContainer = document.getElementById('todaysLoadsContainer');
var activeContainer = document.getElementById('activeLoadsContainer');
ReactDOM.render(<Table source="/reactloadboard/react/getFutureTableValues.php" />, futureContainer);
ReactDOM.render(<Table source="/reactloadboard/react/getTodaysTableValues.php" />, todaysContainer);
ReactDOM.render(<Table source="/reactloadboard/react/getActiveTableValues.php" />, activeContainer);
And this works when I import the table.js file to the html but I would like it to be more universal in the component usage and remove the
var futureContainer = document.getElementById('futureLoadsContainer');
var todaysContainer = document.getElementById('todaysLoadsContainer');
var activeContainer = document.getElementById('activeLoadsContainer');
ReactDOM.render(<Table source="/reactloadboard/react/getFutureTableValues.php" />, futureContainer);
ReactDOM.render(<Table source="/reactloadboard/react/getTodaysTableValues.php" />, todaysContainer);
ReactDOM.render(<Table source="/reactloadboard/react/getActiveTableValues.php" />, activeContainer);
to be called in the html/php page like the following.
<script type="text/babel" src="/js/reactcomponents/table.js"></script>
<div id="loadboardContainer">
<div class="table-desc">Future Loads</div>
<div id="futureLoadsContainer"></div>
<div class="table-desc">Todays Loads</div>
<div id ="todaysLoadsContainer"></div>
<div class="table-desc">Active Loads</div>
<div id ="activeLoadsContainer"></div>
</div>
var futureContainer = document.getElementById('futureLoadsContainer');
var todaysContainer = document.getElementById('todaysLoadsContainer');
var activeContainer = document.getElementById('activeLoadsContainer');
ReactDOM.render(<Table source="/reactloadboard/react/getFutureTableValues.php" />, futureContainer);
ReactDOM.render(<Table source="/reactloadboard/react/getTodaysTableValues.php" />, todaysContainer);
ReactDOM.render(<Table source="/reactloadboard/react/getActiveTableValues.php" />, activeContainer);
The first way that is working works fine, but if I remove the ReactDom.renders to the html page I am actually putting the component on it says that Component Table doesn't exist. Is there anyway to do this so later on in the application when I have a table all I have to do is import the table.js react component and connect the source and its there? I have looked at other answers on here but they seem to mainly deal with the data for usability.
In order to use the table component in your HTML you need to export it using module.exports since you are not using ES6 for React.
var Table = React.createClass({
...
});
var TableColumns = React.createClass({
...
});
var TableRow = React.createClass({
...
});
//Export the table component
module.exports = Table;
Also the thing is that browser don't have support for JSX so you need to use either of webpack or browserify to transpile your code.
A good tutorial link Webpack tutorial
Well you are almost there.
Here's how you should get it done:
Table.js
var Table = React.createClass({
//Everything stays same here
});
var TableColumns = React.createClass({
// Stays same here too
});
var TableRow = React.createClass({
// This remains same
});
//Export the table component
export default Table;
HTML
<script type="text/babel" src="/js/reactcomponents/table.js"></script>
<div id="loadboardContainer">
<div class="table-desc">Future Loads</div>
<div id="futureLoadsContainer"></div>
<div class="table-desc">Todays Loads</div>
<div id ="todaysLoadsContainer"></div>
<div class="table-desc">Active Loads</div>
<div id ="activeLoadsContainer"></div>
</div>
<script>
var futureContainer = document.getElementById('futureLoadsContainer');
var todaysContainer = document.getElementById('todaysLoadsContainer');
var activeContainer = document.getElementById('activeLoadsContainer');
ReactDOM.render(<Table source="/reactloadboard/react/getFutureTableValues.php" />, futureContainer);
ReactDOM.render(<Table source="/reactloadboard/react/getTodaysTableValues.php" />, todaysContainer);
ReactDOM.render(<Table source="/reactloadboard/react/getActiveTableValues.php" />, activeContainer);
</script>
There are several ways of making a component reusable with React, but since you recently started learning here few things you can go with.
prefer leaning on actual react app instead of browser, but why ? the code you wrote is es5 code and you can write much cleaner and reusable code in ES6.
for starting use any boilerplate so you don't have to dive into the webpack and other complex things at beginning.
now coming to the point of re-usability, if you use it as webpack, it combines all your code into one js file, which you can implement any where on your website.
Now about your code
check this one , about using separate js file
https://facebook.github.io/react/docs/getting-started.html
it has one important piece of information
Note that some browsers (Chrome, e.g.) will fail to load the Separate
file unless it's served via HTTP.
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);"/>
Can I use inline HTML in a script as below by using a library like jsx:
<script src="jsx-transform.js"></script>
<script type="text/jsx">
define('component', function () {
return (<div>test html code</div>);
});
</script>
I was able to write JSX files and inject them into an HTML page using a 'fake' React file.
no-react.js
/**
* Include this script in your HTML to use JSX compiled code without React.
*/
const React = {
createElement: function (tag, attrs, children) {
var element = document.createElement(tag);
for (let name in attrs) {
if (name && attrs.hasOwnProperty(name)) {
let value = attrs[name];
if (value === true) {
element.setAttribute(name, name);
} else if (value !== false && value != null) {
element.setAttribute(name, value.toString());
}
}
}
for (let i = 2; i < arguments.length; i++) {
let child = arguments[i];
element.appendChild(
child.nodeType == null ?
document.createTextNode(child.toString()) : child);
}
return element;
}
};
Then compile your jsx.
test.jsx
const title = "Hello World";
document.getElementById('app').appendChild(
<div>
<h1>{title}</h1>
<h2>This is a template written in TSX, then compiled to JSX by tsc (the Typescript compiler), and finally
injected into a web page using a script</h2>
</div>
);
Resulting compiled 'test.js'
var title = "Hello World";
document.querySelector('#app').appendChild(React.createElement("div", null,
React.createElement("h1", null, title),
React.createElement("h2", null, "This is a template written in TSX, then compiled to JSX by tsc (the Typescript compiler), and finally" + " " + "injected into a web page")));
And finally, the HTML page that includes both scripts.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>no-react</title>
<script src="no-react.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
<script src="test.js"></script>
React renders JSX html syntax to JS using functions such as React.createElement (among others for Fragments and so on). But that all boils down to the #babel/plugin-transform-react-jsx plugin which does the transpiling of this:
return(<div id="hello">Hello World</div>)
into this...
return React.createElement('div', {id: 'hello'}, 'Hello World');
However you can replace React.createElement with you're own function to do this. You can read more on that here: https://babeljs.io/docs/en/next/babel-plugin-transform-react-jsx.html
You should also look at libraries which do exactly this such as nervjs, jsx-render and deku. All of these use a JSX html syntax without react. Some (such as jsx-render) are only focused on converting JSX to the final JS, which might be what you're looking for.
The author of that package wrote an article on it here: https://itnext.io/lessons-learned-using-jsx-without-react-bbddb6c28561
Also Typescript can do this if you use that...but I've no first hand experience with it.
To sum up
You can do it without React, but not without Babel or Typescript.
JSX is not a string-based templating language; it compiles to actual JavaScript function calls. For example,
<div attr1="something" attr2="other">
Here are some <span>children</span>
</div>
transpiles to
React.createElement("div", {attr1: "something", attr2: "other"},
"Here are some ", React.createElement("span", null, "children")
)
I was looking for something like this myself.
A way to write Components and JSX like for simple projects.
Didn't find one that I liked so I've built this:
https://github.com/SagiMedina/Aviya#aviya
Have a look, maybe it will answer your problem as well.
You will need something to transform the JSX into JS function calls. React uses Babel to do this -- you would probably be best off with that too.
There's a library by the creators of Preact that essentially does what you're after called vhtml. The tagline is "Render JSX/Hyperscript to HTML strings, without VDOM".
Here is a copy of the Readme at time of writing:
Usage
// import the library:
import h from 'vhtml';
// tell babel to transpile JSX to h() calls:
/** #jsx h */
// now render JSX to an HTML string!
let items = ['one', 'two', 'three'];
document.body.innerHTML = (
<div class="foo">
<h1>Hi!</h1>
<p>Here is a list of {items.length} items:</p>
<ul>
{ items.map( item => (
<li>{ item }</li>
)) }
</ul>
</div>
);
New: "Sortof" Components!
vhtml intentionally does not transform JSX to a Virtual DOM, instead serializing it directly to HTML. However, it's still possible to make use of basic Pure Functional Components as a sort of "template partial".
When vhtml is given a Function as the JSX tag name, it will invoke that function and pass it { children, ...props }. This is the same signature as a Pure Functional Component in react/preact, except children is an Array of already-serialized HTML strings.
This actually means it's possible to build compositional template modifiers with these simple Components, or even higher-order components.
Here's a more complex version of the previous example that uses a component to encapsulate iteration items:
let items = ['one', 'two'];
const Item = ({ item, index, children }) => (
<li id={index}>
<h4>{item}</h4>
{children}
</li>
);
console.log(
<div class="foo">
<h1>Hi!</h1>
<ul>
{ items.map( (item, index) => (
<Item {...{ item, index }}>
This is item {item}!
</Item>
)) }
</ul>
</div>
);
The above outputs the following HTML:
<div class="foo">
<h1>Hi!</h1>
<ul>
<li id="0">
<h4>one</h4>This is item one!
</li>
<li id="1">
<h4>two</h4>This is item two!
</li>
</ul>
</div>
It looks like the dom-chef package can do this. From the readme:
No API, JSX gets auto transformed into actual DOM elements.
// babel.config.js
const plugins = [
[
'#babel/plugin-transform-react-jsx',
{
pragma: 'h',
pragmaFrag: 'DocumentFragment',
}
]
];
// ...
const {h} = require('dom-chef');
const handleClick = e => {
// <a> was clicked
};
const el = (
<div class="header">
<a href="#" class="link" onClick={handleClick}>Download</a>
</div>
);
document.body.appendChild(el);
You can have a look at documentation: in-browser JSX transform,
and also see Babel documentation
You can achieve what you want, but it is discouraged in production...
Jsx parse the return (<div>test html code</div>); to something like this return React.createElement('div', {...});
then if you don't using react.js, then browser will not know what React is and trigger an error.