[React] React Basic I

install npm install -g create-react-app
create create-react-app APPNAME
start npm start

Concepts

Immutability

React forces immutability.

Strings are immutable by default, when you change them in reality you create a new string and assign it to the same variable name. An immutable variable can never be changed. To update its value, you create a new variable. The same applies to objects and arrays.

Instead of changing an array, to add a new item you create a new array by concatenating the old array, plus the new item.

JSX

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React, { Component } from 'react';
import './App.css';

class App extends Component {
render() {
return (
<div className="App"> // JSX
<h1>test</h1>
</div>
);
// would be compiled to
return React.createElement('div', {className: 'App'}, React.createElement('h1', null, 'test'));
}
}

export default App;

Component

A component is just a javascript function which will return JSX to the DOM

There are two ways of creating components in React:

  • Functional Components (presentational, stateless, dumb components) (best practice)

The has to be included in the

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React from 'react';

const person = () => {
return <p>Person Component</p>
}

export default person;

// in App.js
class App extends Component {
render() {
return (
<div className="App">
<h1>test</h1>
<Person>Children Content</Person>
</div>
);
}
}

// in Person.js
<p>{props.children}</p>
  • Class-based components (containers, smart, stateful components)
1
2
3
class Cmp extends Component { render() {
return <div>Some JSX</div>
}}

Dynamic Content

1
2
3
4
5
6
7
8
9
10
11
// in App.js
class App extends Component {
render() {
return (
<div className="App">
<h1>{ Math.floor(Math.random() * 30) }</h1>
<Person />
</div>
);
}
}

Working with Props

Props are used to pass data in parent and Children components

1
2
3
4
5
6
7
8
9
// in App.js
<Person name="Ted" age="31">My Hobby: Racing</Person>
// in Person.js
return (
<div>
<p>Im {props.name}, and I am {props.age} years old.</p>
<p>{props.children}</p>
</div>
)

Use PropTypes

1
npm install --save prop-types
1
2
3
4
5
6
7
8
9
10
11
12
import PropTypes from 'prop-types';

class Person extends Component {...}

Person.propTypes = {
click: PropTypes.func, // Expect a function for click
name: PropTypes.string,
age: PropTypes.number,
changed: PropTypes.func
}

export default withClass(Person)

State

state can only be used in class extending Components. We use state to store some data of the component itself. The state is used to change the component from within. Usually used to trigger an UI update.

  • Only class-based component can define and use state
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class App extends Component {
state = {
persons: [
{name: 'Max', age: 28},
{name: 'Manu', age: 29},
{name: 'Stephanie', age: 26}
]
}

switchNameHandler = () => {
// DON'T DO THIS this.state.persons[0].name = 'name change';
this.setState({persons: [ // update state with this new one
{name: 'Maxxi', age: 28},
{name: 'Manu', age: 29},
{name: 'Stephanie', age: 27}
]})
}
render() {
return (
<div className="App">
<h1>test</h1>
<button onClick={this.switchNameHandler}>Switch Name</button>
<Person name={this.state.persons[0].name} age="28"></Person>
<Person name={this.state.persons[1].name} age="31">My Hobby: Racing</Person>
</div>
);
}
}

export default App;
  • props and state are CORE concepts of React. Actually, only changes in props and state can trigger React to re-render your components and potentially update the DOM in the browser.
  • The state of the component should only be abled to be changed in a few components in the app, referred as containers

A wrong way to setState

1
2
3
4
this.setState({
persons: persons,
changeCounter: this.state.changeCouter + 1 // this.state is not garanteed to be the exact previous state of the app
});

A better apporach to update state based on the old state

1
2
3
4
5
6
this.setState((prevState, props) => {
return {
persons: persons,
changeCounter: prevState.changeCounter + 1
}
});

Passing methods between components

1
2
3
4
5
6
7
8
9
10
11
12
13
14
render() {
return (
<div className="App">
<h1>test</h1>
<button onClick={this.switchNameHandler.bind(this, 'Maximmm')}>Switch Name</button>
<Person
name={this.state.persons[0].name}
age="28"
click={() => this.switchNameHandler('newName')}></Person>
<Person name={this.state.persons[1].name} age="31">My Hobby: Racing</Person>
</div>
);
}
}

Two Way Binding

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

// App.js
switchNameHandler = (event) => {
// DON'T DO THIS this.state.persons[0].name = 'name change';
this.setState({persons: [ // update state with this new one
{name: 'Max', age: 28},
{name: event.target.value, age: 29},
{name: 'Stephanie', age: 27}
]})
}
render() {
return (
<div className="App">
<h1>test</h1>
<button>Switch Name</button>
<Person
name={this.state.persons[1].name}
age="28"
click={() => this.switchNameHandler('newName')}
changed={this.switchNameHandler}></Person>
<Person
name={this.state.persons[2].name}
age="31">My Hobby: Racing</Person>
</div>
);
}

// Person.js
const person = (props) => {
return (
<div>
<p onClick={props.click}>Im {props.name}, and I am {props.age} years old.</p>
<input type="text" onChange={props.changed} /> // eject event with onChange
</div>
)}