How to set initial state with using ES6 class in React? - reactjs

I have created the below class
class App extends Component{
render() {
return (
<div className="app"></div>
);
}
}
How do i set initial state? getInitialState() isn't working?
what am i doing wrong? The react docs are also not helping.

There is also a shortcut of Jenna's great answer, which doesn't use constructor or this:
class App extends Component {
state = {
text: 'Hello World'
};
render() {
return (
<div>
{this.state.text}
</div>
);
}
}
A simplified example shows that the output is the same in both cases:
Babel with constructor
Babel without constructor
But if we extend a parent class, the transpiled output does differ, since the number of arguments in the constructor is unknown.

import React, { Component } from 'react';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
text: 'Hello World'
};
}
render() {
return (
<div>
{this.state.text}
</div>
);
}
}
You may also want to check out this post about the difference between when to use a constructor and when to use getInitialState.
What is the difference between using constructor vs getInitialState in React / React Native?

Related

ReactJS Question Component function scope and sharing functions

I have a question about ReactJS and components, specifically about how functions interact within the component system.
In this example:
// Index.js
import React from ‘/reactʼ;
import ReactDOM from ‘/react-domʼ;
import App from ‘./App.jsʼ;
ReactDOM.render(<App />, document.getElementById(‘rootʼ));
// App.js
import React from ‘/reactʼ;
class App extends React.Component {
constructor(props) {
super(props);
this.state = {someProp = ‘ʼ};
};
functionA = (e) => { console.log(e);
};
Render() {
return <div><ComponentA /></div>
};
};
export default App;
// ComponentA.js
import React from ‘/reactʼ;
import App from ‘./../App.jsʼ;
class ComponentA extends React.Component {
constructor(props) {
super(props);
this.state = {someProp = ‘ʼ};
};
functionB = App.functionA
Render() {
return(
<div>
<input onSubmit={this.functionB} />
</div>
);
};
};
export default ComponentA;
ComponentA imports App.js and attempts to assign App.functionA to functionB and then call it in the JSX. This results in a failure basically saying that the function is not defined.
I know this is NOT the way to function share (I have learned about passing functions through props etc).
I simply just want to know WHY this does not work, to help me better understand the mechanics of React, and Javascript in general.
Thank you,
Curtis
To call a function from another React component, you can write static methods in ES6 notation. If you are using ES7, then you can also write static properties.
You can write statics inside ES6+ classes this way:
class Component extends React.Component {
static propTypes = {
...
}
static someMethod(){
}
}
Working Demo about static function
My noob brain finally figured it out lol... I think.
Basically because an instance of the class [the App component] was not initialized within the scope of ComponentA, the App function is not accessible.
This made it work (DISCLAIMER: I DO NOT PLAN ON DOING THIS, I KNOW ITS TERRIBLE CODE)
// ComponentA.js
import React from ‘/reactʼ;
import App from ‘./../App.jsʼ;
class ComponentA extends React.Component {
constructor(props) {
super(props);
this.state = {someProp = ‘ʼ};
this.appInstance = new App();
}
functionB = (e) => {
this.appInstance.functionA(e);
}
Render() {
return(
<div>
<input onSubmit={this.functionB} />
</div>
);
}
};
export default ComponentA;

passing an event to a child component in React

I'm new to React and this is a very noob question, but I don't understand why this is not working.
I'm trying to build a simple todo List.
My TodoList.js Component looks like this:
import React, {Component} from 'react';
import TodoItem from './TodoItem';
export default class TodoList extends Component{
constructor(props){
super(props);
this.state = {
todos:[
{
title:"todo1"
},
{
title:"todo3"
},
{
title:"todo2"
}
]
}
}
handleRemove(idx){
alert('works');
}
render(){
var todos = this.state.todos.map(function(t,idx){
return(<TodoItem
remove={this.handleRemove.bind(this,idx)}
title={t.title}
/>)
})
return (
<div>
<h1>To do</h1>
<div>{todos}</div>
</div>
)
}
}
My child Component looks like this:
import React, {Component} from 'react';
export default class TodoItem extends Component{
render(){
return (
<div>{this.props.title}
<button onClick={this.props.remove}>X</button>
</div>
)
}
}
But I get a TypeError with "Cannot read property 'handleRemove' of undefined". I'm wondering why inside the map function {this} is undefined?
I tried to put this this.handleRemove = this.handleRemove.bind(this) into the constructor.
Didn't change anything. Shouldn't this also be defined inside the .map() ?
You need to put this as the second argument
If a thisArg parameter is provided to map, it will be used as
callback's this value. Otherwise, the value undefined will be used as
its this value. The this value ultimately observable by callback is
determined according to the usual rules for determining the this seen
by a function.
on map:
render(){
var todos = this.state.todos.map(function(t,idx){
return(<TodoItem
remove={this.handleRemove.bind(this,idx)}
title={t.title}
/>)
}, this)
return (
<div>
<h1>To do</h1>
<div>{todos}</div>
</div>
)
}
}
Alternatively, you can use an ES6 arrow function to automatically preserve the current this context:
var todos = this.state.todos.map((t,idx) => {
return(<TodoItem
remove={this.handleRemove.bind(this,idx)}
title={t.title}
/>)
})

ReactJS - How to use method from other component of other file? [duplicate]

I have two components. I want to call a method of the first component from the second component. How can I do it?
Here is my code.
First Component
class Header extends React.Component{
constructor(){
super();
}
checkClick(e, notyId){
alert(notyId);
}
}
export default Header;
Second Component
class PopupOver extends React.Component{
constructor(){
super();
// here i need to call Header class function check click....
// How to call Header.checkClick() from this class
}
render(){
return (
<div className="displayinline col-md-12 ">
Hello
</div>
);
}
}
export default PopupOver;
You can do something like this
import React from 'react';
class Header extends React.Component {
constructor() {
super();
}
checkClick(e, notyId) {
alert(notyId);
}
render() {
return (
<PopupOver func ={this.checkClick } />
)
}
};
class PopupOver extends React.Component {
constructor(props) {
super(props);
this.props.func(this, 1234);
}
render() {
return (
<div className="displayinline col-md-12 ">
Hello
</div>
);
}
}
export default Header;
Using statics
var MyComponent = React.createClass({
statics: {
customMethod: function(foo) {
return foo === 'bar';
}
},
render: function() {
}
});
MyComponent.customMethod('bar'); // true
Well, actually, React is not suitable for calling child methods from the parent. Some frameworks, like Cycle.js, allow easily access data both from parent and child, and react to it.
Also, there is a good chance you don't really need it. Consider calling it into existing component, it is much more independent solution. But sometimes you still need it, and then you have few choices:
Pass method down, if it is a child (the easiest one, and it is one of the passed properties)
add events library; in React ecosystem Flux approach is the most known, with Redux library. You separate all events into separated state and actions, and dispatch them from components
if you need to use function from the child in a parent component, you can wrap in a third component, and clone parent with augmented props.
UPD: if you need to share some functionality which doesn't involve any state (like static functions in OOP), then there is no need to contain it inside components. Just declare it separately and invoke when need:
let counter = 0;
function handleInstantiate() {
counter++;
}
constructor(props) {
super(props);
handleInstantiate();
}
You could do this to call a method of the child component from the parent component.
import React from 'react';
class Header extends React.Component {
constructor() {
super();
this.childComponentRef;
}
getChildComponent = (childComponent) => {
this.childComponentRef = childComponent;
this.childComponentRef.sayHi();
}
render() {
return (
<ChildComponent getChildComponent={this.getChildComponent} />
)
}
};
class ChildComponent extends React.Component {
componentDidMount () {
this.props.getChildComponent(this);
}
sayHi = () => {
alert("hi");
}
render() {
return (
<div className="displayinline col-md-12 ">
Hello
</div>
);
}
}
export default Header;

Get propery of other React component in a library

I'm writing a library full of ReactJS components, so Flux should not be used, since it's a library.
I have a component, a ThemeProvider.
import React from 'react';
class OfficeUIThemeProvider extends React.Component {
constructor(props) {
super(props);
}
render() {
return null;
}
}
OfficeUIThemeProvider.propTypes = {
theme: React.PropTypes.oneOf(['Office2016']).isRequired,
color: React.PropTypes.oneOf(['Light-Blue', 'Blue', 'Green', 'Orange', 'Purple', 'Red']).isRequired
};
export default OfficeUIThemeProvider;
I return null in the render() method since this component should not render anything.
Then I do have a simple component, a button.
import React from 'react';
class OfficeUIButton extends React.Component {
constructor(props) {
super(props);
}
render() {
return <div className={"officeui-button"}>
<span className="{officeui-button-label}">{this.props.label}</span>
</div>
}
}
OfficeUIButton.propTypes = {
label: React.PropTypes.string.isRequired,
};
export default OfficeUIButton;
Now, I want the button to have specific classes, based on the values provided in the ThemeProvider.
A simple solution would be to render the OfficeUIButton component directly in my ThemeProvider render() method but this is not a valid solution since I'm developing a library and don't want to couple things.
An application using this library should work as:
ReactDOM.render(
<OfficeUIThemeProvider theme='Office2016' color='Light-Blue'>
<OfficeUIButton label="To..." />
</OfficeUIThemeProvider>,
document.getElementById('app')
);
But, this renders nothing since my ThemeProvider return null○ in it'srender` method.
How can this be accomplished?
Kind regards,
OfficeUIButton is child component of OfficeUIThemeProvider, so I suppose you should try:
class OfficeUIThemeProvider extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
{this.props.children}
</div>
);
}
}

componentDidMount method not triggered when using inherited ES6 react class

I'm trying to use ES6 classes inside of React, and want all my components to inherit certain methods, however as soon as I try to extend a component which extends the React.Component class, the componentDidMount method doesn't trigger and hence nothing gets rendered. The code I'm using:
BaseComponent.jsx
import React from 'react';
class BaseComponent extends React.Component {
constructor() {
super();
console.log('BaseComponent constructor');
}
render() {
return (
<div>Hello, Im the base component</div>
);
}
}
export default BaseComponent;
ExampleComponent.jsx
import BaseComponent from './BaseComponent';
class ExampleComponent extends BaseComponent {
constructor(props) {
super(props);
}
componentDidMount() {
console.log('exampleComponent mounted');
}
render() {
return (
<div>Hello, Im the example component</div>
);
}
}
export default ExampleComponent;
App.jsx
import React from 'react';
React.render(<ExampleComponent />, document.body);
I'm using React 0.13.3, and using babelify 6.1.2 to transpile.
The string 'exampleComponent mounted' never gets logged to console, and nothing is rendered. Any ideas what I'm doing wrong?
I'm not sure about the approach, but this code also works:
export default class Service extends BaseComponent {
componentDidMount(...args) {
super.componentDidMount.apply(this, args);
}
}
UPD: this is considered to be a bad practice though:
a) https://medium.com/#dan_abramov/how-to-use-classes-and-sleep-at-night-9af8de78ccb4
b) https://medium.com/#dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750
I think, the problem is that you cannot create deeper class-structures for react components. Also, you shouldn't have to need it. On your example the BaseComponent is useless anyway.
Try this instead:
import React from 'react';
export default class ExampleComponent extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log('exampleComponent mounted');
}
render() {
return (
<div>Hello, Im the example component</div>
);
}
}
If you want to create 'BaseComponents', you could implement them as mixins or simply as 'sub components'.
This could look like this:
import React from 'react';
import BaseComponent from './BaseComponent';
export default class ExampleComponent extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log('exampleComponent mounted');
}
render() {
return (
<div>
<div>Hello, Im the example component</div>
<BaseComponent />
</div>
);
}
}
EDIT: Also possible:
import React from 'react';
import BaseComponent from './BaseComponent';
export default class ExampleComponent extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log('exampleComponent mounted');
}
render() {
return (
<BaseComponent
<div>Hello, Im the example component</div>
</BaseComponent>
);
}
}
// BaseComponent.js
render() {
return {
<div>
<div>Hello, Im the base component</div>
{this.props.children}
</div>
}
}
EDIT #2: Above code works fine with es5/jsx syntax.
DEMO

Resources