An open API service indexing awesome lists of open source software.

https://github.com/bunlong/react-in-practice

Clear examples, explanations, and resources for React v.16.6.x (React Hooks)
https://github.com/bunlong/react-in-practice

react react-16 react-hook react-hooks react-practise react-suspense reactjs

Last synced: about 1 year ago
JSON representation

Clear examples, explanations, and resources for React v.16.6.x (React Hooks)

Awesome Lists containing this project

README

          

# React in Practice (React v.16.6.x)

### Table of contents:

Hooks

1. [Introducing](#hooksIntroducing)
2. [A Brief of Hook](#hooksBrief)
1. [Using the State Hook](./hooks/using_the_state_hook.md "Using the State Hook")
2. [Using the Effect Hook](./hooks/using_the_effect_hook.md "Using the Effect Hook")
3. [Building Your Own Hooks](./hooks/building_your_own_hooks.md "Building Your Own Hooks")
4. [Rules of Hooks](./hooks/rules_of_hooks.md "Rules of Hooks")
5. [Hooks APIs](./hooks/hooks_apis.md "Hooks APIs")

Code-Splitting

1. [import()](#codeSplittingImport)
2. [lazy](#codeSplittingLazy)
3. [Suspense](#codeSplittingSuspense)
4. [Error boundaries](#codeSplittingErrorBoundaries)
5. [Route-based code splitting](#codeSplittingRouteBased)
6. [Named Exports](#codeSplittingNamedExports)

[Context](#context)

[React Context API Pattern](#reactContextAPIPattern)

Composition

Portals

memo

---

## Hooks

### 1. Introducing

Hooks are a new feature that lets you use state and other React features without writing a class. They're released in React v16.7.0.

Hooks are functions that let you "hook into" React state and lifecycle features from function components. Hooks don't work inside classes they let you use React without classes.

### 2. A Brief of Hook

**State Hook**

Renders a counter example. When you click the button, it increments the value:

Using React Hook

```javascript
import React, { useState } from 'react';

function App() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0);

return (


You clicked {count} times


setCount(count + 1)}>
Click me


);
}

export default App;
```

- `useState` is a Hook, we call it inside a function component to add some local state to it.
- `useState` returns a pair: the current state value and a function that lets you update it, you can call this function from an event handler or somewhere else.
- `useState` has only one argument is the initial state, in the example above 0 is the initial state.

Using React Class

```javascript
import React from 'react';

class App extends React.Component {
state = {
count: 0,
}

setCount = () => {
this.setState({
count: this.state.count + 1,
});
}

render() {
return (


You clicked {this.state.count} times


this.setCount()}>
Click me


);
}
}

export default App;
```

Declaring multiple state variables.

You can use State Hook more than once in a single component:

```javascript
function withManyStates() {
// Declare multiple state variables!
const [name, setName] = useState('Brian');
const [age, setAge] = useState(77);
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
}
```

React also provides a few built-in Hooks like `useState`. You can also create custom Hooks to reuse stateful behavior between different components. We'll look at the built-in Hooks first.

> You can learn more about the State Hook on a dedicated page: [Using the State Hook](./hooks/using_the_state_hook.md "Using the State Hook").

**Effect Hook**

You likely performe data fetching, subscriptions, or manually changing the DOM from React components using React lifecycle ( componentDidMount, componentDidUpdate and componentWillUnmount ) in React classes. We call these operations "side effects".

The Effect Hook, `useEffect`, adds the ability to perform side effects from a function component. It serves the same purpose as React lifecycle ( componentDidMount, componentDidUpdate, and componentWillUnmount ) in React classes, but unified into a single API.

Example, this component sets the document title after React updates the DOM:

Using React Hook

```javascript
import React, { useState, useEffect } from 'react';

function App() {
const [count, setCount] = useState(0);

// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
// Update the document title using the browser API
document.title = `You clicked ${count} times`;
});

return (


You clicked {count} times


setCount(count + 1)}>
Click me


);
}

export default App;
```

- When you call `useEffect`, you're telling React to run your "effect" function after flushing changes to the DOM.
- Effects are declared inside the component so they have access to its props and state. By default, React runs the effects after every render including the first render.

Using React Class

```javascript
import React from 'react';

class App extends React.Component {
state = {
count: 0,
}

componentDidMount() {
document.title = `You clicked ${this.state.count} times`;
}

componentDidUpdate() {
document.title = `You clicked ${this.state.count} times`;
window.addEventListener('resize', this.setCount);
}

setCount = () => {
this.setState({
count: this.state.count + 1,
});
}

render() {
return (


You clicked {this.state.count} times


this.setCount()}>
Click me


);
}
}

export default App;
```

Example, React would clean up `resize` event when the component unmounts, as well as before re-running the effect due to a subsequent render.

Using React Hook

```javascript
import React, { useState, useEffect } from 'react';

function App() {
const [width, setWidth] = useState(window.innerWidth);

// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
// Clean up resize event
return () => {
window.removeEventListener('resize', handleResize);
};
});

return (


Window width: {width}



);
}

export default App;
```

Using React Class

```javascript
import React, { Component } from 'react';

class App extends Component {
state = {
width: window.innerWidth,
}

UNSAFE_componentWillMount() {
window.addEventListener('resize', this.handleResize);
}

componentWillUnmount() {
window.removeEventListener('resize', this.handleResize);
}

handleResize = () => {
this.setState({
width: window.innerWidth,
});
}

render() {
return (


Window width: {this.state.width}



);
}
}

export default App;
```

Just like with `useState`, you can use multiple effect in a component:

Using React Hook

```javascript
import React, { useState, useEffect } from 'react';

function App() {
const [width, setWidth] = useState(window.innerWidth);

useEffect(() => {
document.title = `Window width: ${width}`;
});

// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
// Clean up resize event
return () => {
window.removeEventListener('resize', handleResize);
};
});

return (


Window width: {width}



);
}

export default App;
```

Hooks let you organize side effects in a component by what pieces are related (such as adding and removing a event or subscription), rather than forcing a split based on lifecycle methods.

> You can learn more about the Effect Hook on a dedicated page: [Using the Effect Hook](./hooks/using_the_effect_hook.md "Using the Effect Hook").

**Building Your Own Hooks**

Well, sometimes we want to reuse some stateful logic between components. Traditionally, there were two popular solutions to this problem: `higher-order components` and `render props`. Custom Hooks let you do this, but without adding more components to your tree.

Earlier on this page, we introduced a App component that calls the `useState` and `useEffect` Hooks to get window width and display on browser title. Let's say we also want to reuse this App logic in another component.

First, we'll extract this logic into a custom Hook called `useWindowWidth` and `useDocumentTitle`:

```javascript
function useDocumentTitle(title) {
useEffect(() => {
document.title = title;
});
}

function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
// Clearn up
return () => {
window.removeEventListener('resize', handleResize);
};
});
return width;
}
```

Now we can use it from the component:

```javascript
import React, { useState, useEffect } from 'react';

function App() {
const width = useWindowWidth();

useDocumentTitle(`Window width: ${width}`);

return (


Window width: {width}



);
}

export default App;
```

The state of these components is completely independent. Hooks are a way to reuse stateful logic, not state itself. In fact, each call to a Hook has a completely isolated state and so you can even use the same custom Hook twice in one component.

To build your own hooks you need to follow the `useSomething` naming convention. If a function's name starts with "use" and it calls other Hooks, we say it is a custom Hook.

You can write custom Hooks that cover a wide range of use cases like form handling, animation, declarative subscriptions, timers, and probably many more we haven't considered.

> You can learn more about the Building Your Own Hooks on a dedicated page: [Building Your Own Hooks](./hooks/building_your_own_hooks.md "Building Your Own Hooks").

**Rules of Hooks**

Hooks are JavaScript functions, but they impose two additional rules:

- Only call Hooks at the top level. Don't call Hooks inside loops, conditions, or nested functions.
- Only call Hooks from React function components. Don't call Hooks from regular JavaScript functions. (There is just one other valid place to call Hooks is your own custom Hooks.)

The better way you can use a [linter plugin](https://www.npmjs.com/package/eslint-plugin-react-hooks) to enforce these rules automatically.

> You can learn more about the Rules of Hooks on a dedicated page: [Rules of Hooks](./hooks/rules_of_hooks.md "Rules of Hooks").

---

## Code-Splitting

### 1. import()

The best way to introduce code-splitting into your app is through the dynamic `import()` syntax.

Before:

```javascript
import { add } from './math';

console.log(add(16, 26));
```

After:

```javascript
import("./math").then(math => {
console.log(math.add(16, 26));
});
```

### 2. lazy

Before:

```javascript
import OtherComponent from './OtherComponent';

function MyComponent() {
return (




);
}
```

After:

```javascript
import React, {lazy} from 'react';

const OtherComponent = lazy(() => import('./OtherComponent'));

function MyComponent() {
return (




);
}
```

This will automatically load the bundle containing the `OtherComponent` when this component gets rendered.

`lazy` takes a function that must call a dynamic import(). This must return a Promise which resolves to a module with a default export containing a React component.

### 3. Suspense

If the module containing the `OtherComponent` is not yet loaded by the time `MyComponent` renders, we must show some fallback content while we're waiting for it to load - such as a loading indicator. This is done using the `Suspense component`.

```javascript
import React, {lazy, Suspense} from 'react';
const OtherComponent = lazy(() => import('./OtherComponent'));

function MyComponent() {
return (
Loading...}>


);
}
```

### 4. Error boundaries

> Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed.
>
> Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them.

A class component becomes an error boundary once it defines either (or both) of the lifecycle methods `static getDerivedStateFromError()` or `componentDidCatch()`. Use `static getDerivedStateFromError()` to render a fallback UI after an error has been thrown. Use `componentDidCatch()` to log error information.

```javascript
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}

static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}

componentDidCatch(error, info) {
// You can also log the error to an error reporting service
// logErrorToMyService(error, info);
}

render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return

Something went wrong.

;
}

return this.props.children;
}
}
```

> Note that error boundaries only catch errors in the components below them in the tree.

Once you've created your Error Boundary, you can use it anywhere above your lazy components to display an error state when there's a network error.

```javascript
import MyErrorBoundary from './MyErrorBoundary';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));

const MyComponent = () => (



Loading...
}>







);
```

### 5. Route-based code splitting

Deciding where in your app to introduce code splitting can be a bit tricky.

> A good place to start is with routes.

Here's an example of how to setup route-based code splitting into your app using libraries like [React Router](https://reacttraining.com/react-router "React Router") with `lazy`.

```javascript
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import React, { Suspense, lazy } from 'react';

const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));

const App = () => (

Loading...}>






);
```

### 6. Named Exports

> `lazy` currently only supports default exports.

```javascript
// ManyComponents.js
export const MyComponent = /* ... */;
export const MyUnusedComponent = /* ... */;
```

If the module you want to import uses named exports, you can create an intermediate module that reexports it as the default.

```javascript
// MyComponent.js
export { MyComponent as default } from "./ManyComponents.js";
```

Use like so:

```javascript
// MyApp.js
import React, { lazy } from 'react';
const MyComponent = lazy(() => import("./MyComponent.js"));
```

---

## Context

> Context provides a way to pass data through the component tree without having to pass props down manually at every level.

- When to Use Context
- Before You Use Context
- API
- React.createContext
- Context.Provider
- Class.contextType
- Context.Consumer
- Examples
- Dynamic Context
- Updating Context from a Nested Component
- Consuming Multiple Contexts
- Caveats

### When to Use Context

> Context is designed to share data that can be considered as "global" for a tree of React components, such as the current authenticated user, theme, or preferred language.

> Using context, we can avoid passing props through intermediate elements.

### Before You Use Context

> Context is primarily used when some data needs to be accessible by many components at different nesting levels.

### API

Context API provides a way to pass data through the component tree without having to pass props down manually to every level. In React, data is often passed from a parent to its child component as a property.

Using the new React Context API depends on three main steps:
1. Passing the initial state to `React.createContext`. This function then returns an object with a `Provider` and a `Consumer`.
2. Using the `Provider` component at the top of the tree and making it accept a prop called `value`. This value can be anything.
3. Using the `Consumer` component anywhere below the Provider in the component tree to get a subset of the state.

#### React.createContext

```javascript
const MyContext = React.createContext(defaultValue);
```

`React.createContext` which is passed the initial value (defaultValue). This returns an object with a Provider and a Consumer.

#### Context.Provider

```javascript

```

The `Provider` component is used higher in the tree and accepts a prop called value (which can be anything).

#### Class.contextType

- `contextType` is used to:
- Perform a side-effect at mount using the value of Context
- Render something based on the value of Context

```javascript
class MyClass extends React.Component {
static contextType = MyContext;
componentDidMount() {
let value = this.context;
/* perform a side-effect at mount using the value of MyContext */
}
componentDidUpdate() {
let value = this.context;
/* ... */
}
componentWillUnmount() {
let value = this.context;
/* ... */
}
render() {
let value = this.context;
/* render something based on the value of MyContext */
}
}
```

#### Context.Consumer

```javascript

{value => /* render something based on the context value */}

```

The `Consumer` component is used anywhere below the provider in the tree and accepts a prop called "children" which must be a function that accepts the value and must return a react element (JSX).

#### Examples

##### Dynamic Context

`theme-context.js`

```javascript
import React from 'react';

export const themes = {
dark: {
foreground: '#ffffff',
background: '#222222',
},
light: {
foreground: '#000000',
background: '#eeeeee',
},
};

export const ThemeContext = React.createContext(
themes.dark, // default value
);
```

`themed-button.js`

```javascript
import React from 'react';

import {ThemeContext} from './theme-context';

class ThemedButton extends React.Component {
render() {
let props = this.props;
let theme = this.context;

return (

);
}
}

ThemedButton.contextType = ThemeContext;

export default ThemedButton;
```

`App.js`

```javascript
import React, { Component } from 'react';

import {ThemeContext, themes} from './theme-context';
import ThemedButton from './themed-button';

// An intermediate component that uses the ThemedButton
function Toolbar(props) {
return (

Change Theme

);
}

class App extends Component {
constructor(props) {
super(props);
this.state = {
theme: themes.light,
};

this.toggleTheme = () => {
this.setState(state => ({
theme:
state.theme === themes.dark
? themes.light
: themes.dark,
}));
};
}

render() {
// The ThemedButton button inside the ThemeProvider
// uses the theme from state while the one outside uses
// the default dark theme
return (









);
}
}

export default App;
```

##### Updating Context from a Nested Component

It is often necessary to update the context from a component that is nested somewhere deeply in the component tree.

In this case you can pass a function down through the context to allow consumers to update the context:

`theme-context.js`

```javascript
import React from 'react';

export const themes = {
dark: {
foreground: '#ffffff',
background: '#222222',
},
light: {
foreground: '#000000',
background: '#eeeeee',
},
};

// Make sure the shape of the default value passed to
// createContext matches the shape that the consumers expect!
export const ThemeContext = React.createContext({
theme: themes.dark,
toggleTheme: () => {},
});
```

`theme-toggler-button.js`

```javascript
import React from 'react';

import {ThemeContext} from './theme-context';

function ThemeTogglerButton() {
// The Theme Toggler Button receives not only the theme
// but also a toggleTheme function from the context
return (

{({theme, toggleTheme}) => (

Toggle Theme

)}

);
}

export default ThemeTogglerButton;
```

`App.js`

```javascript
import React, { Component } from 'react';

import {ThemeContext, themes} from './theme-context';
import ThemeTogglerButton from './theme-toggler-button';

class App extends Component {
constructor(props) {
super(props);

this.toggleTheme = () => {
this.setState(state => ({
theme:
state.theme === themes.dark
? themes.light
: themes.dark,
}));
};

// State also contains the updater function so it will
// be passed down into the context provider
this.state = {
theme: themes.light,
toggleTheme: this.toggleTheme,
};
}

render() {
// The entire state is passed to the provider
return (



);
}
}

function Content() {
return (




);
}

export default App;
```

## React Context API Pattern

The **Context API** is a neat way to pass state across the app without having to use props.

The Context API was introduced to allow you to pass state (and enable the state to update) across the app, without having to use props for it.

The React team suggests to stick to props if you have just a few levels of children to pass, because it’s still a much less complicated API than the Context API.

In many cases, it enables us to avoid using Redux, simplifying our apps a lot, and also learning how to use React.

How does it work?

You create a context using `React.createContext()`, which returns a Context object.:

```javascript
const { Provider, Consumer } = React.createContext()
```

Then you create a wrapper component that returns a **Provider** component, and you add as children all the components from which you want to access the context:

```javascript
class Container extends React.Component {
constructor(props) {
super(props)
this.state = {
something: 'hey'
}
}

render() {
return (
{this.props.children}
)
}
}

class HelloWorld extends React.Component {
render() {
return (



)
}
}
```

I used Container as the name of this component because this will be a global provider. You can also create smaller contexts.

Inside a component that’s wrapped in a Provider, you use a **Consumer** component to make use of the context:

```javascript
class Button extends React.Component {
render() {
return (

{context => {context.state.something}}

)
}
}
```

You can also pass functions into a Provider value, and those functions will be used by the Consumer to update the context state:

```javascript
this.setState({something: 'ho!'})
{this.props.children}

/* ... */

{(context) => (
{context.state.something}
)}

```

You can create multiple contexts, to make your state distributed across components, yet expose it and make it reachable by any component you want.

When using multiple files, you create the content in one file, and import it in all the places you use it:

```javascript
//context.js
import React from 'react'
export default React.createContext()

//component1.js
import Context from './context'
//... use Context.Provider

//component2.js
import Context from './context'
//... use Context.Consumer
```