VDone Demo VDone Demo
Home
  • Articles

    • JavaScript
  • Study Notes

    • JavaScript Tutorial
    • Professional JavaScript
    • ES6 Tutorial
    • Vue
    • React
    • TypeScript: Build Axios from Scratch
    • Git
    • TypeScript
    • JS Design Patterns
  • HTML
  • CSS
  • Technical Docs
  • GitHub Tips
  • Node.js
  • Blog Setup
  • Learning
  • Interviews
  • Miscellaneous
  • Practical Tips
  • Friends
About
Bookmarks
  • Categories
  • Tags
  • Archives
GitHub (opens new window)

Nikolay Tuzov

Backend Developer
Home
  • Articles

    • JavaScript
  • Study Notes

    • JavaScript Tutorial
    • Professional JavaScript
    • ES6 Tutorial
    • Vue
    • React
    • TypeScript: Build Axios from Scratch
    • Git
    • TypeScript
    • JS Design Patterns
  • HTML
  • CSS
  • Technical Docs
  • GitHub Tips
  • Node.js
  • Blog Setup
  • Learning
  • Interviews
  • Miscellaneous
  • Practical Tips
  • Friends
About
Bookmarks
  • Categories
  • Tags
  • Archives
GitHub (opens new window)
  • 核心概念

  • 高级指引

  • Hook

    • Hooks Overview
      • What is a Hook?
      • useState (State Hook)
        • Declaring Multiple State Variables
      • Effect Hook (Side Effect Hook)
        • useEffect (Lifecycle Hook)
        • "Cleaning Up" Side Effects
      • Rules of Hooks
      • Custom Hooks (Encapsulating Hook Logic)
      • Other Hooks
    • Using the State Hook
    • Using the Effect Hook
    • Rules of Hooks
    • Custom Hooks
  • 案例演示

  • 《React》笔记
  • Hook
xugaoyi
2021-03-31
Contents

Hooks Overview

# 01. Hooks Overview

Hooks let you use state and other React features without writing a class.

# What is a Hook?

A Hook is a special function that lets you "hook into" React state and lifecycle features from function components.

  1. Hooks don't work inside classes -- they let you use React without classes.

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

# useState (State Hook)

Pattern:

const [<getter>, <setter>] = useState(<initialValue>)
1

The three values above can be custom-named:

  • State getter variable name
  • State setter method name
  • Initial value
    • The initial value can be a number, string, object, array, etc.

Example:

import React, { useState } from 'react';

function Example() {
  // Declare a new state variable called "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# Declaring Multiple State Variables

function ExampleWithManyStates() {
  // Declare multiple state variables!
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
  // ...
}
1
2
3
4
5
6
7

# Effect Hook (Side Effect Hook)

You've likely performed data fetching, subscriptions, or manually changing the DOM from React components before. We call these operations "side effects" (or "effects" for short).

# useEffect (Lifecycle Hook)

useEffect is an Effect Hook that adds the ability to perform side effects from a function component. It serves the same purpose as componentDidMount, componentDidUpdate, and componentWillUnmount in React classes, but unified into a single API. (We'll show examples comparing useEffect to these methods in Using the Effect Hook (opens new window).)

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

import React, { useState, useEffect } from 'react';
function Example() {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Runs after the first DOM render and after every update
    // Uses the browser API to update the document title
    document.title = `You clicked ${count} times`;
  });
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

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.

# "Cleaning Up" Side Effects

Effects may also optionally specify how to "clean up" after them by returning a function. For example, this component uses an effect to subscribe to a friend's online status, and cleans up by unsubscribing from it:

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

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  useEffect(() => { // Runs after component mount and update
    // Subscribe
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => { // Runs when component unmounts
      // Unsubscribe
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

In this example, React would unsubscribe from our ChatAPI when the component unmounts, as well as before re-running the effect due to a subsequent render. (If you want, there's a way to tell React to skip re-subscribing (opens new window) if the props.friend.id we passed to ChatAPI didn't change.)

Just like with useState, you can use more than a single useEffect in a component:

function FriendStatusWithCounter(props) {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }
  // ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

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

For more details

You can learn more about useEffect in this chapter: Using the Effect Hook (opens new window)

# 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 -- your own custom Hooks. We'll learn about them in a moment.)

We also provide a linter plugin (opens new window) to enforce these rules automatically. We understand these rules might seem limiting or confusing at first, but they are essential to making Hooks work well.

For more details

You can learn more about these rules in this chapter: Rules of Hooks (opens new window).

# Custom Hooks (Encapsulating Hook Logic)

Sometimes, we want to reuse some stateful logic between components. Traditionally, there were two popular solutions: higher-order components (opens new window) and render props (opens new window). Custom Hooks let you do this without adding more components to your tree.

Earlier, we introduced a FriendStatus component that calls the useState and useEffect Hooks to subscribe to a friend's online status. Suppose we want to reuse this subscription logic in another component.

First, we'll extract this logic into a custom Hook called useFriendStatus:

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

// Extract logic for reuse
function useFriendStatus(friendID) {
  // State is independent for each call
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

It takes friendID as an argument, and returns whether our friend is online.

Now we can use it from both components:

function FriendStatus(props) {
  const isOnline = useFriendStatus(props.friend.id);
  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
function FriendListItem(props) {
  const isOnline = useFriendStatus(props.friend.id);
  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

The state of each component 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 -- so you can even use the same custom Hook twice in one component.

Custom Hooks are more of a convention than a feature. If a function's name starts with "use" and it calls other Hooks, we say it is a custom Hook. The useSomething naming convention lets our linter plugin find bugs in the code using Hooks.

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. We are excited to see what custom Hooks the React community will come up with.

For more details

You can learn more about custom Hooks in this chapter: Building Your Own Hooks (opens new window).

# Other Hooks

There are a few less commonly used but useful built-in Hooks. For example, useContext (opens new window) lets you subscribe to React context without introducing nesting:

function Example() {
  const locale = useContext(LocaleContext);
  const theme = useContext(ThemeContext);
  // ...
}
1
2
3
4
5

And useReducer (opens new window) lets you manage local state of complex components with a reducer:

function Todos() {
  const [todos, dispatch] = useReducer(todosReducer);  // ...
1
2

For more details

You can learn more about all built-in Hooks in this chapter: Hooks API Reference (opens new window).

Edit (opens new window)
#React
Last Updated: 2026/03/21, 12:14:36
Advanced Guides
Using the State Hook

← Advanced Guides Using the State Hook→

Recent Updates
01
How I Discovered Disposable Email — A True Story
06-12
02
Animations in Grid Layout
09-15
03
Renaming a Git Branch
08-11
More Articles >
Theme by VDone | Copyright © 2026-2026 Nikolay Tuzov | MIT License | Telegram
  • Auto
  • Light Mode
  • Dark Mode
  • Reading Mode