Table of Contents
- React
- Redux
1 – React
Use React
// Import React and ReactDOM
import React from 'react'
import ReactDOM from 'react-dom'
// Render JSX into a DOM element
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
// Render Component into a DOM element
ReactDOM.render(
<MyComponent />,
document.getElementById('root')
);
JSX
// JSX produce React Element
const item = <h1>My JSX Element</h1>;
// Use curly braces to embed some Javascript
const item = <div>{getContent()}</div>;
// Use camelCase for attribute name
const item = <div className="example"></div>;
// Use curly braces to embed some Javascript
const item = <img src={image.url}></img>;
// Self close if tag is empty
const item = <div />;
Components
// Stateless Functional Component
function Heading(props) {
return <h1>{props.title}</h1>;
}
// Stateless Functional Component (with arrow function)
const Heading = (props) => {
return <h1>{props.title}</h1>;
}
// ES6 Class Component, can have states
class Heading extends React.Component {
render() {
return <h1>{this.props.title}</h1>;
}
}
// Always start component names with capital
<Heading />
Render
// Return React Element
render() {
return <div>Example of return<div />
}
// Return Another Component
render() {
return <MyComponent />
}
// Return String
render() {
return 'Return a string works!'
}
// Return Numbers (rendered as text node)
render() {
return 100
}
// Return nothing
render() {
return null
}
Component Lifecycle
componentWillMount() {
}
componentDidMount() {
// Call after the component output has been rendered in the DOM
}
componentWillReceiveProps() {
}
shouldComponentUpdate() {
}
componentWillUpdate() {
}
componentDidUpdate() {
}
componentWillUnmount() {
}
componentDidCatch() {
}
Props (Properties)
Props are immutable.
// Component with a single valid argument : props
function Heading(props) {
return <h1>{props.title}</h1>;
}
State
State are locals and fully controlled by the component itself.
// Update state with setState, except in constructor
this.setState({
title: 'Updated title',
});
// Set state with previous state
this.setState((prevState, props) => {
return {count: prevState.count + 1};
});
// Declare initial state in constructor
class Heading extends React.Component {
constructor(props) {
super(props);
this.state = {title: 'My title'};
}
}
// Do not update state directly
this.state.title = 'Hello';
// Lifting state up to share state between component
class Wrapper extends React.Component {
constructor(props) {
super(props);
this.handleInputChange = this.handleInputChange.bind(this);
this.state = {value: ''};
}
handleInputChange(value) {
this.setState({value});
}
render() {
const value = this.state.value;
return (
<Input value={value} onInputChange={this.handleInputChange} />
);
}
}
class Input extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.props.onInputChange(e.target.value);
}
render() {
const value = this.props.value;
return <input value={value} onChange={this.handleChange} />;
}
}
Handling Event
// React Event are in camelCase
<button onClick={handleClick}>
Action
</button>
// Use preventDefault instead of return false
function handleClick(e) {
e.preventDefault();
}
// Bind this to use it in the callback
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
// Pass data to callback
<button onClick={(e) => this.deleteItem(id, e)}>Delete item</button>
<button onClick={this.deleteItem.bind(this, id)}>Delete item</button>
Conditional Rendering
// Using if operator with props
function Heading(props) {
const isHome = props.isHome;
if (isHome) {
return <HomeHeading />;
}
return <PageHeading />;
}
// Using if operator with state
render() {
const isHome = this.state.isHome;
let heading = null;
if (isHome) {
heading = <HomeHeading />;
} else {
heading = <PageHeading />;
}
return (
<div>
{heading}
</div>
);
}
// Using ternary operator
<div>
{isHome ? <HomeHeading /> : <PageHeading />}
</div>
// Using logical operator
<div>
{messages.length > 0 &&
<h1>
You have messages
</h1>
}
</div>
// Prevent component from rendering
function Modal(props) {
if (!props.isShow) {
return null;
}
return (
<div>
Modal
</div>
);
}
Portal
import { createPortal } from "react-dom";
class MyPortalComponent extends React.Component {
render() {
return createPortal(
this.props.children,
document.getElementById("node"),
);
}
}
Fragment
const Fragment = React.Fragment;
render() {
return (
<Fragment>
Some text.
<h2>A heading</h2>
Even more text.
</Fragment>
);
}
render() {
return (
<React.Fragment>
Some text.
<h2>A heading</h2>
Even more text.
<React.Fragment>
);
}
render() {
return (
<>
<ComponentA />
<ComponentB />
</>
);
}
Forms
Controlled Components
// In controlled component, each state mutation have an handler function
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({value: e.target.value});
}
handleSubmit(e) {
alert('Submitted value: ' + this.state.value);
e.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="text" value={this.state.value} onChange={this.handleChange} />
<input type="submit" value="Submit" />
</form>
);
}
}
// Force to uppercase in handler
handleChange(e) {
this.setState({value: e.target.value.toUpperCase()});
}
// in React use a value attribute</span>
<span class="pl-k"><</span>textarea value<span class="pl-k">=</span>{<span class="pl-c1">this</span>.<span class="pl-smi">state</span>.<span class="pl-c1">value</span>} onChange<span class="pl-k">=</span>{<span class="pl-c1">this</span>.<span class="pl-smi">handleChange</span>} <span class="pl-k">/</span><span class="pl-k">></span></pre>
</div>
// use a value and not a selected attribute
select value={this.state.value} onChange={this.handleChange}>
option value="a">Option A/option>
option value="b">Option B/option>
/select>
//
select multiple={true} value={['a', 'b']}>
// Handle multiple inputs with name attribute
handleInputChange(e) {
const target = e.target;
const value = target.value;
const name = target.name;
this.setState({
[name]: value
});
}
render() {
return (
form>
input name="firstName" onChange={this.handleInputChange} />
input name="lastName" onChange={this.handleInputChange} />
/form>
);
}
<h3><a id="user-content-react-without-jsx" class="anchor" href="#react-without-jsx" aria-hidden="true"></a>React without JSX</h3>
// This two elements are similar :
const element = (
h1 className="heading">
Hello!
/h1>
);
const element = React.createElement(
'h1',
{className: 'heading'},
'Hello!'
);
<h3><a id="user-content-typechecking-props-with-proptypes" class="anchor" href="#typechecking-props-with-proptypes" aria-hidden="true"></a>Typechecking props with PropTypes</h3>
// Use PropTypes
import PropTypes from 'prop-types';
// Prop is an optional array
MyComponent.propTypes = {
optionalArray: PropTypes.array,
};
// Prop is an optional boolean
MyComponent.propTypes = {
optionalBool: PropTypes.bool,
};
// Prop is an optional function
MyComponent.propTypes = {
optionalFunc: PropTypes.func,
};
// Prop is an optional number (integer, float...)
MyComponent.propTypes = {
optionalNumber: PropTypes.number,
};
// Prop is an optional object
MyComponent.propTypes = {
optionalObject: PropTypes.object,
};
// Prop is an optional string
MyComponent.propTypes = {
optionalString: PropTypes.string,
};
// Prop is an optional symbol
MyComponent.propTypes = {
optionalSymbol: PropTypes.symbol,
};
// Prop is an optional node (numbers, strings, elements, array, fragment)
MyComponent.propTypes = {
optionalNode: PropTypes.node,
};
<h3><a id="user-content-create-react-app" class="anchor" href="#create-react-app" aria-hidden="true"></a>Create React App</h3>
# Create new app
create-react-app my-app
<h3><a id="user-content-fetch-datas" class="anchor" href="#fetch-datas" aria-hidden="true"></a>Fetch datas</h3>
// Use componentDidMount hook with fetch
class PostsList extends Component {
constructor(props) {
super(props);
this.state = {posts: []};
}
componentDidMount() {
fetch('https://example.com/posts')
.then(response => response.json())
.then(data => this.setState({ posts: data.posts }));
.catch(error => console.log(error));
}
}
// Use Axios library to fetch datas
import axios from 'axios';
componentDidMount() {
axios.get('/post', {
params: {ID: 123}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
<h2><a id="user-content-2---redux" class="anchor" href="#2---redux" aria-hidden="true"></a>2 - Redux</h2>
<h3><a id="user-content-install-redux" class="anchor" href="#install-redux" aria-hidden="true"></a>Install Redux</h3>
npm install --save redux
# Install react binding
npm install --save react-redux
# Install dev tools
npm install --save-dev redux-devtools
<h3><a id="user-content-actions" class="anchor" href="#actions" aria-hidden="true"></a>Actions</h3>
// Declare action type
const SUBMIT_FORM = 'SUBMIT_FORM'
// Action shape with payload
{
type: SUBMIT_FORM,
payload: {
firstName: 'John',
lastName: 'Doe',
}
}
// Action shape without payload
{
type: SUBMIT_FORM,
}
// Declare action creator
function submitForm(formData) {
return {
type: SUBMIT_FORM,
payload: {
firstName: formData.firstName,
lastName: formData.lastName,
}
}
}
<h3><a id="user-content-reducers" class="anchor" href="#reducers" aria-hidden="true"></a>Reducers</h3>
// Declare an initial state
const initialState = {
firstName: '',
lastName: '',
city: '',
}
// Declare a minimal reducer
function userReducer(state = initialState, action) {
return state;
}
// Handle action in reducer
function userReducer(state = initialState, action) {
switch (action.type) {
case SUBMIT_FORM:
return {
...state,
firstName: action.payload.firstName,
lastName: action.payload.lastName,
city: action.payload.city,
};
default:
return state;
}
}
</article>
</div>
<p>