React

What Is React?

React is

  1. a JavaScript library
  2. for building user interfaces (?)
  3. lets you compose complex UIs from small and isolated pieces of code called “components”.

A component

  1. takes in parameters, called props (short for “properties”), and
  2. returns a hierarchy of views to display via the render method.

Hello World

ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);

JSX

const element = <h1>Hello, world!</h1>;

Embedding Expressions in JSX

const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;
ReactDOM.render(
element,
document.getElementById('root')
);

Specifying Attributes with JSX

const element = <div tabIndex="0"></div>;
const element = <img src={user.avatarUrl}></img>;

Rendering Elements

Unlike browser DOM elements, React elements are plain objects, and are cheap to create.

Rendering an Element into the DOM

const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));

Updating the Rendered Element

React elements are immutable. Once you create an element, you can’t change its children or attributes. The only way to update the UI is to create a new element, and pass it to ReactDOM.render().

function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(element, document.getElementById('root'));
}
setInterval(tick, 1000);

React Only Updates What’s Necessary

React DOM compares the element and its children to the previous one, and only applies the DOM updates necessary to bring the DOM to the desired state.

Components and Props

Components are like JavaScript functions. They accept arbitrary inputs (called “props”) and return React elements describing what should appear on the screen.

Function and Class Components

The simplest way to define a component is to write a JavaScript function:

function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}

This function is a valid React component because it accepts a single “props” (which stands for properties) object argument with data and returns a React element. We call such components “function components” because they are literally JavaScript functions.

You can also use an ES6 class to define a component:

class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}

The above two components are equivalent from React’s point of view.

Rendering a Component

Elements can also represent user-defined components:

const element = <Welcome name="Sara" />;

Props are Read-Only

Whether you declare a component as a function or a class, it must never modify its own props.

All React components must act like pure functions with respect to their props.

State and Lifecycle

function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);

Converting a Function to a Class

You can convert a function component like Clock to a class in five steps:

  1. Create an ES6 class, with the same name, that extends React.Component.
  2. Add a single empty method to it called render().
  3. Move the body of the function into the render() method.
  4. Replace props with this.props in the render() body.
  5. Delete the remaining empty function declaration.
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.date.toLocaleTimeString()}.</h2>
</div>
);
}
}

Adding Local State to a Class

class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}

Adding Lifecycle Methods to a Class

We can declare special methods on the component class to run some code when a component mounts and unmounts:

componentDidMount() {
}
componentWillUnmount() {
}

These methods are called “lifecycle methods”.

class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);

Using State Correctly

Do Not Modify State Directly

// Wrong
this.state.comment = 'Hello';
// Correct
this.setState({comment: 'Hello'});

State Updates May Be Asynchronous

React may batch multiple setState() calls into a single update for performance.

Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.

// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
// Correct
this.setState(function(state, props) {
return {
counter: state.counter + props.increment
};
});

State Updates are Merged

When you call setState(), React merges the object you provide into the current state.

The Data Flows Down

Neither parent nor child components can know if a certain component is stateful or stateless, and they shouldn’t care whether it is defined as a function or a class.

A component may choose to pass its state down as props to its child components:

<FormattedDate date={this.state.date} />

The FormattedDate component would receive the date in its props and wouldn’t know whether it came from the Clock’s state, from the Clock’s props, or was typed by hand:

function FormattedDate(props) {
return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}

Handling Events

Handling events with React elements is very similar to handling events on DOM elements. There are some syntax differences:

  • React events are named using camelCase, rather than lowercase.
  • With JSX you pass a function as the event handler, rather than a string.
  • Cannot return false to prevent default behavior in React. You must call preventDefault explicitly.

In HTML:

<button onclick="activateLasers()">
Activate Lasers
</button>
<form onsubmit="console.log('You clicked submit.'); return false">
<button type="submit">Submit</button>
</form>

In React:

<button onClick={activateLasers}>
Activate Lasers
</button>
function Form() {
function handleSubmit(e) {
e.preventDefault();
console.log('You clicked submit.');
}
return (
<form onSubmit={handleSubmit}>
<button type="submit">Submit</button>
</form>
);
}

When you define a component using an ES6 class, a common pattern is for an event handler to be a method on the class.

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>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);

You can use an arrow function in the callback:

class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// This syntax ensures `this` is bound within handleClick
return (
<button onClick={() => this.handleClick()}>
Click me
</button>
);
}
}

The problem with this syntax is that a different callback is created each time the LoggingButton renders.

Passing Arguments to Event Handlers

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

References

Last updated on