React Setup

First things first, where to start!

  • Install Node.js
  • Install yarn: brew install yarn
  • Run: yarn create react-app hello-world
  • Run: yarn start

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')
);

React Component Lifecycle

Each component in React has a lifecycle that you can monitor and manipulate during its three main phases.

React Mounting

constructor()called before anything else, when the component is initiated, and it is the natural place to set up the initial state and other initial values.

Example

class Header extends React.Component {
  constructor(props) {
    super(props);
    this.state = {favoritecolor: "red"};
  }
  render() {
    return (
      <h1>My Favorite Color is {this.state.favoritecolor}</h1>
    );
  }
}

ReactDOM.render(<Header />, document.getElementById('root'));
getDerivedStateFromProps() Called right before rendering the element(s) in the DOM

Example

class Header extends React.Component {
  constructor(props) {
    super(props);
    this.state = {favoritecolor: "red"};
  }
  static getDerivedStateFromProps(props, state) {
    return {favoritecolor: props.favcol };
  }
  render() {
    return (
      <h1>My Favorite Color is {this.state.favoritecolor}</h1>
    );
  }
}

ReactDOM.render(<Header favcol="yellow"/>, document.getElementById('root'));
render()required, and is the method that actual outputs HTML to the DOM.

Example

class Header extends React.Component {
  render() {
    return (
      <h1>This is the content of the Header component</h1>
    );
  }
}

ReactDOM.render(<Header />, document.getElementById('root'));
componentDidMount()called after the component is rendered.

Example

class Header extends React.Component {
  constructor(props) {
    super(props);
    this.state = {favoritecolor: "red"};
  }
  componentDidMount() {
    setTimeout(() => {
      this.setState({favoritecolor: "yellow"})
    }, 1000)
  }
  render() {
    return (
      <h1>My Favorite Color is {this.state.favoritecolor}</h1>
    );
  }
}

ReactDOM.render(<Header />, document.getElementById('root'));

React Updating

getDerivedStateFromProps()This is the first method that is called when a component gets updated.

Example

class Header extends React.Component {
  constructor(props) {
    super(props);
    this.state = {favoritecolor: "red"};
  }
  static getDerivedStateFromProps(props, state) {
    return {favoritecolor: props.favcol };
  }
  changeColor = () => {
    this.setState({favoritecolor: "blue"});
  }
  render() {
    return (
      <div>
      <h1>My Favorite Color is {this.state.favoritecolor}</h1>
      <button type="button" onClick={this.changeColor}>Change color</button>
      </div>
    );
  }
}

ReactDOM.render(<Header favcol="yellow"/>, document.getElementById('root'));
shouldComponentUpdate()you can return a Boolean value that specifies whether React should continue with the rendering or not.

Example

class Header extends React.Component {
  constructor(props) {
    super(props);
    this.state = {favoritecolor: "red"};
  }
  shouldComponentUpdate() {
    return false;
  }
  changeColor = () => {
    this.setState({favoritecolor: "blue"});
  }
  render() {
    return (
      <div>
      <h1>My Favorite Color is {this.state.favoritecolor}</h1>
      <button type="button" onClick={this.changeColor}>Change color</button>
      </div>
    );
  }
}

ReactDOM.render(<Header />, document.getElementById('root'));
render()called when a component gets updated, it has to re-render the HTML to the DOM, with the new changes.

Example

class Header extends React.Component {
  constructor(props) {
    super(props);
    this.state = {favoritecolor: "red"};
  }
  changeColor = () => {
    this.setState({favoritecolor: "blue"});
  }
  render() {
    return (
      <div>
      <h1>My Favorite Color is {this.state.favoritecolor}</h1>
      <button type="button" onClick={this.changeColor}>Change color</button>
      </div>
    );
  }
}

ReactDOM.render(<Header />, document.getElementById('root'));
getSnapshotBeforeUpdate()you have access to the props and state before the update, meaning that even after the update, you can check what the values were before the update.

Example

class Header extends React.Component {
  constructor(props) {
    super(props);
    this.state = {favoritecolor: "red"};
  }
  componentDidMount() {
    setTimeout(() => {
      this.setState({favoritecolor: "yellow"})
    }, 1000)
  }
  getSnapshotBeforeUpdate(prevProps, prevState) {
    document.getElementById("div1").innerHTML =
    "Before the update, the favorite was " + prevState.favoritecolor;
  }
  componentDidUpdate() {
    document.getElementById("div2").innerHTML =
    "The updated favorite is " + this.state.favoritecolor;
  }
  render() {
    return (
      <div>
        <h1>My Favorite Color is {this.state.favoritecolor}</h1>
        <div id="div1"></div>
        <div id="div2"></div>
      </div>
    );
  }
}

ReactDOM.render(<Header />, document.getElementById('root'));
componentDidUpdate()called after the component is updated in the DOM.

Example

class Header extends React.Component {
  constructor(props) {
    super(props);
    this.state = {favoritecolor: "red"};
  }
  componentDidMount() {
    setTimeout(() => {
      this.setState({favoritecolor: "yellow"})
    }, 1000)
  }
  componentDidUpdate() {
    document.getElementById("mydiv").innerHTML =
    "The updated favorite is " + this.state.favoritecolor;
  }
  render() {
    return (
      <div>
      <h1>My Favorite Color is {this.state.favoritecolor}</h1>
      <div id="mydiv"></div>
      </div>
    );
  }
}

ReactDOM.render(<Header />, document.getElementById('root'));

Unmounting

componentWillUnmount()called when the component is about to be removed from the DOM.

Example

class Container extends React.Component {
  constructor(props) {
    super(props);
    this.state = {show: true};
  }
  delHeader = () => {
    this.setState({show: false});
  }
  render() {
    let myheader;
    if (this.state.show) {
      myheader = <Child />;
    };
    return (
      <div>
      {myheader}
      <button type="button" onClick={this.delHeader}>Delete Header</button>
      </div>
    );
  }
}

class Child extends React.Component {
  componentWillUnmount() {
    alert("The component named Header is about to be unmounted.");
  }
  render() {
    return (
      <h1>Hello World!</h1>
    );
  }
}

ReactDOM.render(<Container />, document.getElementById('root'));

React Elements and 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 />;

React Fetch data

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);
  });
}

React 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
}

React 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 />

React 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>
  );
}

React 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>

React Forms

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()});
}

<textarea> in React use a value attribute

<textarea value={this.state.value} onChange={this.handleChange} />

<select> 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> value can have an array for multiple values

<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>
  );
}

React 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 />
    </>
  );
}

React Portal

import { createPortal } from "react-dom";

class MyPortalComponent extends React.Component {
  render() {
    return createPortal(
      this.props.children,
      document.getElementById("node"),
    );
  }
}

React Type checking props with PropTypes

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, };

React State

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} />;
  }
}