CDATA block displays as a commented out in React - javascript

I'm trying to render some html inside <![CDATA[ ]] block passed to dangerouslySetInnerHTML in ReactJS and this content renders as a commented out. E.g. I get <!--[CDATA[Where is my text?]]--> instead of [CDATA[Where is my text?]] in the DOM.
const HTML_OK = '<pre>My text looks good</pre>'
const HTML_CDATA = '<pre><![CDATA[Where is my text?]]></pre>'
class Hello extends React.Component {
render() {
return <div dangerouslySetInnerHTML={{ __html: this.props.html }} />;
}
}
ReactDOM.render(
<div>
<Hello html={HTML_OK} />
<Hello html={HTML_CDATA} />
</div>,
document.getElementById('root')
);
<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="root">
<!-- This element's contents will be replaced with your component. -->
</div>
How can I get <![CDATA[ ]] displays ok in my React application?

Related

React.Component and React.PureComponent show different behaviour

I am adding runnable code snippets below. see the difference
First one is React.PureComponent version
class App extends React.PureComponent {
render() {
console.log('re-render')
return (
<div>
<span>I am parent</span>
{this.props.children}
</div>
)
}
}
ReactDOM.render(
<App>
<div>
I am the child
</div>
</App>,
document.getElementById('app')
)
//setTimeout(render, 1000)
<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="app"></div>
Second one is React.Component version
class App extends React.Component {
render() {
console.log('re-render')
return (
<div>
<span>I am parent</span>
{this.props.children}
</div>
)
}
}
ReactDOM.render(
<App>
<div>
I am the child
</div>
</App>,
document.getElementById('app')
)
//setTimeout(render, 1000)
<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="app"></div>
Why the second one runs successfully, but not the first one?? I tried exploring for the reason, but didnot find any good reason
I may be wrong, but I don't think React.PureComponent exists in version 15.1.0.
The error you get ("Uncaught TypeError: Super expression must either be null or a function, not undefined") is usually triggered by a typo, or by extending a class that doesn't exist (see more details in this SO post).
My suggestion is to keep your 3rd party libs up to date and use the latest version of React in this case.
Here's your own example after the react upgrade:
class App extends React.PureComponent {
render() {
console.log('re-render')
return (
<div>
<span>I am parent</span>
{this.props.children}
</div>
)
}
}
ReactDOM.render(
<App>
<div>
I am the child
</div>
</App>,
document.getElementById('app')
)
//setTimeout(render, 1000)
<script src="https://unpkg.com/react#16.2.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.2.0/umd/react-dom.development.js"></script>
<div id="app"></div>
React.PureComponent is added after 15.3.0 version because of which there is a error in first case.
If you want your first case to work please check the snippet. I have updated the react version.
class App extends React.PureComponent {
render() {
console.log('re-render')
return (
<div>
<span>I am parent</span>
{this.props.children}
</div>
)
}
}
ReactDOM.render(
<App>
<div>
I am the child
</div>
</App>,
document.getElementById('app')
)
//setTimeout(render, 1000)
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="app"></div>
For reference please check
react-release-version
React.PureComponent will not work in your case because you are using a older version of ReactJS. Actually the support for React.PureComponent was introduced with React 15.3 on June 29, 2016.

Laravel 5.5 render a React component in a blade view with data from the controller

My goals is to be able to do something like this in my blade view.
<Example name="{{ $user->name }}" />
But this doesn't render anything.
When I do: <div id="example"></div>it renders the component without the props value which is normal.
So I am trying to pass data that came from my controller to my React component as a prop.
I am not sure if it's even possible.
This is my App.js:
require('./components/Example');
This is my Example.js component:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Example extends Component {
render() {
return (
<div className="container">
<div className="row">
<div className="col-md-8 col-md-offset-2">
<div className="panel panel-default">
<div className="panel-heading">Example</div>
<div className="panel-body">
Hello, {this.props.name}
</div>
</div>
</div>
</div>
</div>
);
}
}
if (document.getElementById('example')) {
ReactDOM.render(<Example />, document.getElementById('example'));
}
I do it like this eg. in index.blade.php
<div id="main" data-user_name="{{$user->name}}" />
Then in Main.js
const Main = (props) => {
return (
<div>
<Component {...props} />
</div>
);
}
if(document.getElementById('main')) {
const el = document.getElementById('main')
const props = Object.assign({}, el.dataset)
ReactDOM.render(<Main {...props} />, el);
}
This is perhaps a slightly cleaner solution than the others suggested. We don't need to specify each prop we pass in using this method either.
In your blade file:
<div id="react-component" data-foo='{{ $foo }}' data-bar='{{ $bar }}'>
On a side note, if $foo is something that isn't JSON, e.g a Laravel Collection or an array, we can apply an additional method: $foo->toJson().
In your component:
if (document.getElementById('react-component')) {
const component = document.getElementById('react-component');
const props = Object.assign({}, component.dataset);
ReactDOM.render(<ReactComponent {...props} />, component);
}
You'll then have access to all the props you pass in using the data attribute from your html. Just like any other react you can access your props inside of your component like: this.props.foo
You can do it like this..
#extends('layouts.app')
#section('script')
<script type="text/javascript">
ReactDOM.render(<Example name="{{ $user->name }}"/>, document.getElementById('example'));
</script>
#endsection
#section('content')
<div id="example"></div>
#endsection
But better solution would be AJAX request to some controller that returns json data.
Best solution for you will this laravel package
laracasts/PHP-Vars-To-Js-Transformer

React: How to render a component twice in a page?

I have a component build in ReactmyComponent.js
ReactDOM.render(
<MyComponent />,
document.getElementById('my-id')
);
In my Html, I want to render it twice, the HTML is as following:
<div id='my-id></div>
some html
<div id='my-id></div>
I want react render twice in this page, but it only render once for the second div. Is there anyway to render it twice?
You can't have the same id for two or more elements in HTML. Use different ids
<div id='my-id-one></div>
some html
<div id='my-id-two></div>
and call the ReactDOM.render separately for each id.
ReactDOM.render(
<MyComponent />,
document.getElementById('my-id-one')
);
ReactDOM.render(
<MyComponent />,
document.getElementById('my-id-two')
);
It looks like you want to render it in 2 different places, with non-React code in between. To do that, you'll want to give your divs different IDs:
<div id='my-id></div>
some html
<div id='my-other-id></div>
Then render the component to each div:
ReactDOM.render(
<MyComponent />,
document.getElementById('my-id')
);
ReactDOM.render(
<MyComponent />,
document.getElementById('my-other-id')
);
You could do
ReactDOM.render(
<div>
<MyComponent />
<MyComponent />
</div>, document.getElementById('my-id') );
Or You could also have two div tags with different id
<div id='one'></div>
some html
<div id='two'></div>
then
ReactDOM.render(
<MyComponent />,
document.getElementById('one')
);
ReactDOM.render(
<MyComponent />,
document.getElementById('two')
);
Another option is to use a class to define elements to render in:
<div id="my-id-one" class="render-here"></div>
some html
<div id="my-id-two" class="render-here"></div>
Then in js:
let elements = document.getElementsByClassName('render-here');
elements.map(element => ReactDOM.render(
<MyComponent />,
element
));

Show loading icon before first react app initialization

What is the standard way of showing a loader icon before browser downloads all js files and loads react application.
Can I do something like this without breaking anything?
<div id="content" class="app">
Loading...
</div>
Yes.
Once your javascript has loaded, you can replace Loading... by rendering your react app into the same <div>
render(
<App />,
document.getElementById('content')
);
One way of doing this using component life cycle methods.
class App extends React.Component {
constructor(props){
super(props);
this.state = {
loading: true
};
}
componentWillMount(){
this.setState({loading: true}); //optional
}
componentDidMount(){
this.setState({loading: false})
}
render() {
return (
<section className="content">
{this.state.loading && 'loading...'} {/*You can also use custom loader icon*/}
<p>Your content comes here</p>
{this.props.children}
</section>
);
}
}
ReactDOM.render(<App />, document.getElementById("app"));
<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="app">
</div>

React rendering output from 'Marked' as text

I am using the Marked library with React. The problem I am having is that output from Marked renders as text when it included proper HTML elements. Here is the problem Code:
class Main extends React.Component{
render() {
console.log(this)
console.log(marked('I am using __markdown__.'));
return (
<div className="container">
<div className="row">
<div className="col-md-6">
{marked('I am using __markdown__.')}
</div>
<div className="col-md-6">
<h1>Oh hello</h1>
</div>
</div>
</div>
)
}
};
React.render( <Main />, document.getElementById('app'));
and the html:
<div id="app"></div>
thanks.
Use dangerouslySetInnerHTML. React prevents you from xss, and this is the escape hatch.
<div
className="col-md-6"
dangerouslySetInnerHTML={{
__html: marked('I am using __markdown__.')
}}
/>

Categories