How to use React.Component with renderToString method? - reactjs

I tried to do the server side render using renderToString method.
function handleRender(req, res) {
const html = renderToString(
<Counter />
);
res.send(renderFullPage(html));
}
function renderFullPage(html) {
return `
<!doctype html>
<html>
<head>
<title>React Universal Example</title>
</head>
<body>
<div id="app">${html}</div>
<script src="/static/bundle.js"></script>
</body>
</html>
`
}
If the component like following it works:
Counter.js
const Counter = () => {
function testClick(){
console.log('test');
}
return (
<div>
<div onClick={testClick.bind(this)}>
test
</div>
</div>
);
};
export default Counter;
However, if I change Counter.js into following:
class Counter extends React.Component {
testClick(){
console.log('click');
}
render() {
return (
<div>
<div onClick={this.testClick.bind(this)}>
test btn
</div>
</div>
)
}
}
export default Counter;
It will show errors:
Uncaught Error: locals[0] does not appear to be a `module` object with Hot Module replacement API enabled. You should disable react-transform-hmr in production by using `env` section in Babel configuration.
So how to use React.Component with renderToString method?
I minimize the project and push to Github. Please have a look.
https://github.com/ovojhking/ssrTest/tree/master

Related

Error: Target container is not a DOM element ( React/Nextjs)

I have created a context component in React to return a message across all my React pages.
I am getting the error in the subject. Looked at other questions in stackoverflow but none could help me.
Here is the code:
message.js
function Message(props) {
const messageCtx = useContext(MessageBannerContext);
return ReactDOM.createPortal(
<div>
<p>Message</p>
<button>More info</button>
<button onClick={messageCtx.hideMessage}>Ok</button>
</div>,
useEffect(() => {
document.getElementById('message');
}, [])
);
}
export default Message;
_document.js
class MyDocument extends Document {
render() {
return (
<Html>
<Head />
<body>
<Main />
<DeferNextScript />
</body>
<div id="message"></div>
</Html>
);
}
}
export default MyDocument;
Any ideas why I am getting the error in the subject?
Nextjs is run in the server, so the Document Object isn't defined. I've always struggled with that, however you can try a package named jsdom.

How to use WebView to show React jsx file

I can't see any support to React jsx local file. How can I use them in WebView ? Can someone help me .
I'm using in this case like this:
<WebView
source={{
uri: isAndroid
? 'file:///android_asset/android_asset/index.jsx'
: 'index.jsx'
}}
allowUniversalAccessFromFileURLs={true}
onShouldStartLoadWithRequest={request => {
return true
}}
useWebKit={false}
/>
UPDATE
I tried for hours but I can't find the way how to import React file to Javascript.
this is my react file like:
index.jsx
import * as React from 'react';`
export class TVChartContainer extends React.PureComponent {
componentDidMount(){ // Do something}
render(){
return (
<div
id={this.props.containerId}
className={'TVChartContainer'}
/>
);
}
}
You need to get HTML string. In WEB React you can render JSX by ReactDom but in ReactNative you can't do it.
The easiest way is generating html string according to your jsx and data. You can put everthing there. I show you several examples.
class MyInlineWeb extends Component {
componentDidMount(){ // Do something}
renderHtmlAndroid = (data) => {
return `<div>
<style>
.block {}
</style>
<div class="block">${data}<div>
<div>`
}
renderHtmliOs = (data) => {
return `<!DOCTYPE html>
<html>
<head>
<title>Title</title>
<meta charset="UTF-8" />
</head>
<body>
<div id="app">${data}</div>
</body>
</html>`
}
render() {
return (
<WebView
originWhitelist={['*']}
source={{html: isAndroid ? this.renderHtmlAndroid([]) : this.renderHtmliOs([])}}
/>
);
}
}

Script with jsx and script without jsx not working on the same page

I have a page where I want to test some react code. Both scripts are working independently, if they are alone in the page. If I add both, the script with jsx does not work. Is there an explanation for that behavior? Is it not allowed?
There is nothing about the code. I am guessing the imports cannot live together.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="index.css">
<title>My Website</title>
</head>
<body>
<div id="myroot"></div>
<div id="myBabel"></div>
<script src="https://unpkg.com/react#16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<!-- Load our React component. -->
<script src="js/index2.js"></script>
<script type="text/babel" src="js/index.jsx"></script>
</body>
</html>
Here the index2.js contents:
class App extends React.Component {
render() {
return React.createElement("div", null, React.createElement("h1", null, " the list "));
}
}
ReactDOM.render(React.createElement(App,null,null),
document.getElementById("myroot"));
And here a React with jsx:
class App extends React.Component {
state = {
/* Initial State */
input: "",
reversedText: ""
};
/* handleChange() function to set a new state for input */
handleChange = event => {
const value = event.target.value;
this.setState({
input: value
});
};
/* handleReverse() function to reverse the input and set that as new state for reversedText*/
handleReverse = event => {
event.preventDefault();
const text = this.state.input;
this.setState({
reversedText: text
.split("")
.reverse()
.join("")
});
};
render() {
return (
<React.Fragment>
{ /* handleReverse() is called when the form is submitted */}
<form onSubmit={this.handleReverse}>
<div>
{ /* Render input entered */}
<label>Text: {this.state.input}</label>
</div>
<div>
{ /* handleChange() is triggered when text is entered */ }
<input
type="text"
value={this.state.input}
onChange={this.handleChange}
placeholder="Enter a text"
/>
</div>
<div>
<button>Reverse Text</button>
</div>
</form>
{ /* Render reversed text */}
<p>Reversed Text: {this.state.reversedText}</p>
</React.Fragment>
);
}
}
ReactDOM.render(<App />, document.getElementById("myBabel"));
Like I said, the imports are working alone but both at the same time in the HTML page are not.
class List extends React.Component {
render() {
return React.createElement("div", null, React.createElement("h1", null, " the list "));
}
}
ReactDOM.render(React.createElement(List,null,null),
document.getElementById("myroot"));
If you check the console logs for your code you will find this error -
Uncaught SyntaxError: Identifier 'App' has already been declared.
You have both your components identified as App. So React needs different identifiers to keep track of each component. I changed one of the class name from App to List. This will work. Make sure to name your components.

How to pass a json array in react?

First of all I want to clear this I am using cdn for react and using ajax for fetching the details from the json file.
So,I have a json file reactjs.json which looks like...
[
{
"e64fl7exv74vi4e99244cec26f4de1f":[ "image_1.jpg","image_2.jpg"]
}
]
index.html
<!DOCTYPE html>
<html>
<head>
<title>Image Viewer-Static</title>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6.15.0/babel.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/babel">
class FetchDemo extends React.Component {
constructor(props) {
super(props);
this.state = {
images: []
};
}
componentDidMount() {
axios.get('reactjs.json').then(res => {
console.log(res.data);
this.setState({ images: res.data });
});
}
render() {
const { images } = this.state;
return (
<div>
{this.state.images.map((images, index) => (
<PicturesList key={index} apikeys={images.e64fl7exv74vi4e99244cec26f4de1f} />
))}
</div>
);
}
}
class PicturesList extends React.Component {
render() {
return (
<img src={this.props.apikeys} alt={this.props.apikeys}/>
);
}
}
ReactDOM.render(
<FetchDemo/>,
document.getElementById("root")
);
</script>
</body>
</html>
I want to show the image named image_1.jpg,image_2.jpg but this.props.apikeys fetch the value like image_1.jpg,image_2.jpg
images
But I want that it gives two values and show the two image.
I tried a lot to solve this but fails.Any suggestion and help will be welcomed.
Here you are setting the array [ "image_1.jpg","image_2.jpg"] to apiKeys in
<PicturesList key={index} apikeys={images.e64fl7exv74vi4e99244cec26f4de1f} />
So when you try to set the image src here
<img src={this.props.apikeys} alt={this.props.apikeys}/>
what you are setting as this.props.apikeys to src is an array. You have to handle the two images in the array separately to set the source of each image as a String. Try as follows.
{this.props.apikeys.map((image, index) => (
<img src={image} alt={image}/>
))}
since you already have the json file in the file structure you can just import and use it..
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
import reactjsJSON from "./reactjs.json";
class FetchDemo extends React.Component {
constructor(props) {
super(props);
this.state = {
images: reactjsJSON
};
}
** Edit: **
Your html file
<!DOCTYPE html>
<html>
<head>
<title>Image Viewer-Static</title>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6.15.0/babel.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/babel">
class FetchDemo extends React.Component {
constructor(props) {
super(props);
this.state = {
images: []
};
}
componentDidMount() {
axios.get('/reactjs.json').then(res => {
console.log(res.data);
this.setState({ images: res.data });
});
}
render() {
const { images } = this.state;
return (
<div>
{ this.state.images.map(imageObjs =>
Object.keys(imageObjs).map(key =>
imageObjs[key].map((image, index) => (
<PicturesList key={index} apikeys={image} />
))
)
)}
</div>
);
}
}
class PicturesList extends React.Component {
render() {
console.log(this.props)
return (
<img src={this.props.apikeys} alt={this.props.apikeys}/>
);
}
}
ReactDOM.render(
<FetchDemo/>,
document.getElementById("root")
);
</script>
</body>
</html>
Your JSON, tested for all possibilities, replaced with dummy images
[
{
"e64fl7exv74vi4e99244cec26f4de1f": [
"https://picsum.photos/200?image=2",
"https://picsum.photos/200?image=2"
],
"e64fl7exv74vi4e99244cec26f4deop": [
"https://picsum.photos/200?image=2",
"https://picsum.photos/200?image=2"
]
},
{
"e64fl7exv74vi4e99244cec26f4de1g": [
"https://picsum.photos/200?image=2",
"https://picsum.photos/200?image=2"
]
}
]
serve both the files in same http server and check the output.... since both files are served from same server u can add './' path to fetch and get JSON data...
Looks to me like you are receiving this JSON repose & then setting a JSON object into your state. Try looking at
JSON.parse()
. Your also setting the whole JSON object to your images array. You need select a key.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse
I write a demo in codesandbox: https://codesandbox.io/s/oorn5o162q, you can check it out.
I use two real image urls in json, and refine your component code.

integrating js code inside react component

I have converted a component that displays chart bar, and it requires this js snippet to run, what is the correct way of integrating it inside my JSX code?
<script>
/** START JS Init "Peity" Bar (Sidebars/With Avatar & Stats) from sidebar-avatar-stats.html **/
$(".bar.peity-bar-primary-avatar-stats").peity("bar", {
fill: ["#2D99DC"],
width: 130,
})
</script>
I have seen this libraries on npm website, but they mostly deal with external scripts not internal
here is my component:
import React, { Component } from 'react';
export default class App extends Component {
render() {
return (
<div>
"How can I render js code here?"
</div>
);
}
}
You can use refs and componentDidMount callback in order to initialize jquery plugins, like so
class App extends React.Component {
componentDidMount() {
$(this.barChart).peity("bar", {
fill: ["#2D99DC"], width: 130
});
}
render() {
return <div>
<div ref={ (node) => { this.barChart = node } }>
<span class="bar">5,3,9,6,5,9,7,3,5,2</span>
<span class="bar">5,3,2,-1,-3,-2,2,3,5,2</span>
<span class="bar">0,-3,-6,-4,-5,-4,-7,-3,-5,-2</span>
</div>
</div>;
}
}
ReactDOM.render(
<App />,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/peity/3.2.1/jquery.peity.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container"></div>
You should use componentDidMount lifecycle hook.
Add this to your component code:
componentDidMount() {
$(".bar.peity-bar-primary-avatar-stats").peity("bar", {
fill: ["#2D99DC"],
width: 130,
})
}

Resources