React.Component and React.PureComponent show different behaviour - javascript

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.

Related

2 stack frames were collapsed. Target container is not a DOM element

My code has compiled successfully without any errors, but on my browser I'm getting this instead of output Target container is not a DOM element. Why is that? What am I missing?
I've tried React.createElement but it did not work.
import React from 'react';
import ReactDOM from 'react-dom'
class Greeting extends React.Component {
constructor (props){
super(props);
this.setState = {
name: '',
greeting: `Good ${this.props.time},`
}
this.onChange = this.onChange.bind(this)
}
onChange(e){
this.setState ({
name: e.target.value
})
}
render(){
return(
<div className="Container">
<section className="section" >
<label className="label">Name: </label>
<input className="input" name="name" placeholder="Enter your name" onChange={this.onChange} ></input>
</section>
<section>
<p>{this.state.greeting} {this.state.name}</p>
</section>
</div>
)
}
}
export default Greeting;
ReactDOM.render(React.createElement(<Greeting time="morning" />, document.getElementById('app')));
I expect it to show some output, but it does not.
If this is the root component remove export default Greeting;
You should pass the <Greeting /> component directly to the render function:
ReactDOM.render(<Greeting time="morning" />, document.getElementById('app'));
Also, make sure that you add an element to your index.html with id app.
<div id="app"></div>

CDATA block displays as a commented out in React

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?

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

Make button disable using react failed

render(){
const { loading } = this.state;
return(
<div>
{!loading ? <input disabled type='text' /> : <input type='text' />}
</div>
)
}
Above jsx make sense? I didn't get any compliation error, just that I got a warning from react saying Unknown propdisabbedon <input> tag.
How to changed the attr of the button to disabled the correct way? Imagine if my input has lots of class of css, do I need to repeat them too? I felt it's redundant.
You don't need a conditional rendering on the input tag. You can do it the following way
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true
}
}
render(){
const { loading } = this.state;
return(
<div>
<input disabled={loading} type='text'/>
</div>
)
}
}
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>

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>

Categories