- Start a simple React project
- JSX
- React Components
- React Props
- React States
- React Lifecycle
- React Events
- React and forms
- Conditional rendering
- List rendering
- React Router
- Using Axios with React
- Blank React 14.7 project: https://codepen.io/maxencebouret/pen/MQLWaW/
- Tic Tac Toe Project: https://codepen.io/gaearon/pen/oWWQNa/
Commands to launch
$ npm install -g create-react-app # Install globally the `create-react-app` command
$ create-react-app my-app # Create a React project folder "my-app"
$ cd my-app
$ rm -f src/*
$ touch src/index.js src/index.css # Create 2 files
Your src/index.js
file
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
class App extends React.Component {
render() {
return (
<div>
{/* Your application code */}
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
Rule | Example |
---|---|
A JSX is always wraped by a tag |
- <App /> - <MyCoponent>Hello</MyCoponent> - <ul><li>Elt1</li><li>Elt2</li></ul>
|
To put JavaScript, you need to use { and } |
|
... |
|
React is based on Components, and each Component is a classe that extends React.Component
.
// Definition of the ShoppingList component
class ShoppingList extends React.Component {
render() {
return (
<div className="shopping-list">
<h1>Shopping List for {this.props.owner}</h1>
<ul>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
</ul>
</div>
);
}
}
class ShoppingList extends React.Component {
render() {
return (
<div>
<ShoppingList owner="Mark" />
</div>
);
}
}
// Example usage: <ShoppingList name="Mark" />
Component that only needs a render
method can be simplified by a function that just returns a JSX.
Example
function Square(props) {
return (
<button className="square" onClick={props.onClick}>
{props.value}
</button>
);
}
// To use in JSX
<MyComponent myProp={myValue} />
// To use inside MyComponent class
this.prop.myProp
Example
class Board extends React.Component {
renderSquare(i) {
return <Square value={i} />; // Pass a "value" prop to the Square
}
// ...
}
class Square extends React.Component {
render() {
return (
<button className="square">
{this.props.value} {/* Reuse the "value" prop */}
</button>
);
}
}
// You can initialize the state in the Component's constructor
this.state = { firstname: 'Maxence', age: 25 }
// You can get a state value with "this.state" property
this.state.firstname
// You MUST set some state value with "this.setState" method
// Be careful, this opereation is asynchronous
this.setState({firstname: 'Mickaël'})
Example
class Square extends React.Component {
constructor(props) {
super(props);
this.state = { // Init the state
value: null,
};
}
render() {
return (
<button className="square" onClick={() => this.setState({value: 'X'})}> {/* Set the state */}
{this.state.value} {/* Get the state */}
</button>
);
}
}
Mounting:
constructor(props)
: Should starts withsuper(props)
; Perfect to initialize the state and binding methodscomponentWillMount()
render()
: Return the JSX to displaycomponentDidMount()
: Perfect place to call APIs and set up any subscriptions.
Updating:
componentWillReceiveProps(nextProps)
shouldComponentUpdate(nextProps, nextState)
componentWillUpdate(nextProps, nextState)
render()
componentDidUpdate(prevProps, prevState)
Unmounting:
Error Handling:
Handling events with React elements is very similar to handling events on DOM elements. There are some syntactic differences:
- React events are named using camelCase
- With JSX you pass a function as the event handler
Examples
<button onClick={myFunctionToTrigger}>
Activate Lasers
</button>
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button> {/* The same with binding */}
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// This binding is necessary to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
Event Types | Event Names |
---|---|
Clipboard Events | onCopy onCut onPaste |
Composition Events | onCompositionEnd onCompositionStart onCompositionUpdate |
Keyboard Events | onKeyDown onKeyPress onKeyUp |
Focus Events | onFocus onBlur |
Form Events | onChange onInput onInvalid onSubmit |
Mouse Events | onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp |
Selection Events | onSelect |
Touch Events | onTouchCancel onTouchEnd onTouchMove onTouchStart |
UI Events | onScroll |
Wheel Events | onWheel |
Media Events | onAbort onCanPlay onCanPlayThrough onDurationChange onEmptied onEncrypted onEnded onError onLoadedData onLoadedMetadata onLoadStart onPause onPlay onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting |
Image Events | onLoad onError |
Animation Events | onAnimationStart onAnimationEnd onAnimationIteration |
Transition Events | onTransitionEnd |
Other Events | onToggle |
class MyComponent extends React.Component {
showButton() {
if (this.props.isLoggedIn)
return <LogoutButton />
else
return <LoginButton />
}
render() {
let button
if (this.props.isLoggedIn)
button = <LogoutButton />
else
button = <LoginButton />
return (
<div>
{/********** Method 1: Variable **********/}
{button}
{/********** Method 2: Function **********/}
{this.showButton()}
{/********** Method 3: Ternary **********/}
{this.props.isLoggedIn ? <LogoutButton /> : <LoginButton />}
{/********** Method 4: Inline If with Logical && Operator **********/}
{this.props.isLoggedIn && <LogoutButton />}
{!this.props.isLoggedIn && <LoginButton />}
</div>
)
}
}
const students = ['Alice', 'Bob', 'Charly', 'David']
class MyComponent extends React.Component {
showList() {
let list = []
for (let i = 0; i < students.length; i++) {
list.push(<li key={i}>{students[i]}</li>)
}
return list
}
render() {
let list = []
for (let i = 0; i < students.length; i++) {
list.push(<li key={i}>{students[i]}</li>)
}
return (
<ul>
{/********** Method 1: Variable **********/}
{list}
{/********** Method 2: Function **********/}
{this.showList()}
{/********** Method 3: Map **********/}
{students.map((student,i) => <li key={i}>{student}</li>)}
</ul>
)
}
}
Basic Example with 1 input
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
npm install --save react-router-dom
import { BrowserRouter, Route, Link } from 'react-router-dom'
Component | Description | Main Props |
---|---|---|
<BrowserRouter> |
Router Component that should wrap your application | |
<Route> |
When the url matches its props path , it renders its content |
|
<Switch> |
Group <Route> together and display maximum 1 |
|
<Link> |
Replace the <a> tag of HTML in React Router |
|
<NavLink> |
A special version of the <Link> that will add styling attributes to the rendered element when it matches the current URL |
|
A component displayed with <Route>
has access to match
(as this.props.match
or as ({ match }) => ()
) and it is an object containing the following properties:
Property | Type | Description |
---|---|---|
params |
bool | Key/value pairs parsed from the URL corresponding to the dynamic segments of the path |
isExact |
bool | true if the entire URL was matched (no trailing characters) |
path |
string | The path pattern used to match. Useful for building nested <Route> s |
url |
string | The matched portion of the URL. Useful for building nested <Link> s |
npm install --save axios
import axios from 'axios'
class PersonList extends React.Component {
constructor(props) {
super(props)
this.state = {
persons: []
}
}
componentDidMount() {
axios.get(`https://jsonplaceholder.typicode.com/users`)
.then(res => {
const persons = res.data;
this.setState({ persons });
})
}
render() {
return (
<ul>
{ this.state.persons.map(person => <li>{person.name}</li>) }
</ul>
)
}
}
class PersonList extends React.Component {
constructor(props) {
super(props)
this.state = {
name: ''
}
}
handleChange(event) {
this.setState({ name: event.target.value });
}
handleSubmit(event) => {
event.preventDefault();
const user = {
name: this.state.name
};
axios.post(`https://jsonplaceholder.typicode.com/users`, { user })
.then(res => {
console.log(res);
console.log(res.data);
})
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit.bind(this)}>
<label>
Person Name:
<input type="text" name="name" onChange={this.handleChange.bind(this)} />
</label>
<button type="submit">Add</button>
</form>
</div>
)
}
}
// src/api.js
import axios from 'axios';
export default axios.create({
baseURL: `http://jsonplaceholder.typicode.com/`
});
// src/index.js
import API from './api';
// ...
API.delete(`users/${this.state.id}`)
.then(res => {
console.log(res);
console.log(res.data);
})
// ...