“This is the first day of my participation in the Gwen Challenge in November. Check out the details: The last Gwen Challenge in 2021”

React Hook provides a solution for maintaining complex data states.

React 16.8: A Hook is a function that can be applied to function components. React 16.8: A Hook is a function that can be applied to function components.

In general, useState and useEffect hooks and custom hooks can meet most application scenarios.

UseState is generally called State Hook, useEffect is called Effect Hook.

Hook profile

Hook is a new feature in React 16.8. It lets you use state and other React features without having to write a class.

Hook without damaging changes:

  • Totally optional
  • 100% backward compatibility
  • Now available

There are no plans to remove classes from React. There is no need to refactor existing class components. If you are currently writing a React application for classes, you can use hooks in your project.

What problem does Hook solve?

  • Reusing state logic without modifying component structure.
  • Break the interrelated parts of a component into smaller functions to make them easier to understand
  • Get rid of the difficulty for beginners to understand class and this

State Hook

The State Hook is the useState Hook function. Next, compare the Class with the Hook and analyze what useState does.

“Class Sample”

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count0
    };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={()= > this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>); }}Copy the code

“Equivalent Hook Example”

import React, { useState } from 'react';

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

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={()= > setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
Copy the code

UseState accepts unique arguments (numbers, strings… [x, y], where the parameter represents the initial value of state, x represents the updated state, and y represents the function that updated state. When the component is first mounted, state is equal to the pass parameter of useState.

Hook example const [count, setCount] = useState(0) means we declare a state variable called count and a method to update the state variable (function equivalent to this.setstate ()), The values are assigned sequentially using ES6 array deconstruction, where count is assigned x and setCount is assigned y.

In function scope, variables can be used directly without this, so in the Hook example, the state variable and setCount() methods are used directly.

Effect Hook

An Effect Hook is the useEffect Hook function.

UseEffect is equivalent to Raact’s life cycle componentDidMount(), componentDidUpdate(), and compnentWillUnmount().

UseEffect allows you to request data, set up subscriptions, manipulate the DOM, and more.

Next, compare Class and Hook by example and analyze useEffect.

There are two types: effects that do not need to be cleaned and effects that need to be cleaned.

Effect that does not need to be cleaned

“Class Sample”

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count0
    };
  }

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

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={()= > this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>); }}Copy the code

“Equivalent Hook Example”

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

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

  useEffect(() = > {
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={()= > setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
Copy the code

UseEffect is equal to componentDidMount() and componentDidUpdate().

Effects that need to be cleared

Here’s an example of getting a friend’s status for comparison

“Class Sample”

class FriendStatus extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isOnlinenull };
    this.handleStatusChange = this.handleStatusChange.bind(this);
  }

  componentDidMount() {
    ChatAPI.subscribeToFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }
  componentWillUnmount() {
    ChatAPI.unsubscribeFromFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }
  handleStatusChange(status) {
    this.setState({
      isOnline: status.isOnline
    });
  }

  render() {
    if (this.state.isOnline === null) {
      return 'Loading... ';
    }
    return this.state.isOnline ? 'Online' : 'Offline'; }}Copy the code

“Equivalent Hook Example”

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

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

  useEffect(() = > {
    function handleStatusChange(status{
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () = > {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading... ';
  }
  return isOnline ? 'Online' : 'Offline';
}
Copy the code

The Effect to clear refers to the useEffect that returns a function to unsubscribe in place of componentWillUnmount(). UseEffect is equal to a combination of componentDidMount(), componentDidUpdate(), and componentWillUnmount().

Rules of the Hook

There are two rules to follow when using it:

  • Use hooks only at the top level

  • Only the React function calls the Hook

    • Call the Hook in the React function component
    • Call other hooks in custom hooks

Do not call hooks in loops, conditions, or nested functions. The main reason is to ensure that hooks are called in the same order every time they are rendered. This allows React to keep the Hook state correct between multiple useState and useEffect calls.

Here’s an example:

Under normal rules, the execution sequence of multiple hooks is as follows:

function Form({
  // 1. Use the name state variable
  const [name, setName] = useState('Mary');

  // 2. Use an effect for persisting the form
  useEffect(function persistForm({
    localStorage.setItem('formData', name);
  });

  // 3. Use the surname state variable
  const [surname, setSurname] = useState('Poppins');

  // 4. Use an effect for updating the title
  useEffect(function updateTitle({
    document.title = name + ' ' + surname;
  });

  // ...
  
  
  // ------------
  // First render
  // ------------
  useState('Mary')           // 1. Initialize state of variable name with 'Mary'
  useEffect(persistForm)     // 2. Add effect to save form action
  useState('Poppins')        // 3. Initialize the state of the surname variable with 'Poppins'
  useEffect(updateTitle)     // 4. Add effect to update the title

  // -------------
  // Secondary render
  // -------------
  useState('Mary')           // 1. Read state with variable name (argument ignored)
  useEffect(persistForm)     // 2. Replace save form effect
  useState('Poppins')        // 3. Read the state of a variable named surname (parameter ignored)
  useEffect(updateTitle)     // 4. Replace the effect that updates the title

  // ...
  }
Copy the code

React correctly associates the internal state with the corresponding Hook as long as the order of Hook calls remains consistent across multiple renders. But what happens if we put a Hook call (such as persistForm Effect) into a conditional statement?

 // Using Hook in conditional statements violates the first rule
  if(name ! = =' ') {
    useEffect(function persistForm({
      localStorage.setItem('formData', name);
    });
  }
Copy the code

In the first render name! The conditional value is true, so we will execute the Hook. But the next time we render we may have emptied the form and the expression value will be false. The render will skip the Hook, and the order of Hook calls has changed:

useState('Mary')           // 1. Read state with variable name (argument ignored)
// useEffect(persistForm)
useState('Poppins')        // 2 (previously 3). Failed to read state of surname variable
useEffect(updateTitle)     // 3 (previously 4) Failed to replace effect updating title
Copy the code

React does not know what the second useState Hook should return. React would think that the call to the second Hook in this component would correspond to the effect persistForm like the last render, but it does not. From here, subsequent Hook calls are executed ahead of time, resulting in bugs.

** If we want to conditionally execute an effect, we can put the judgment inside the Hook:

useEffect(function persistForm({
    // 👍 places the conditional judgment in effect
    if(name ! = =' ') {
      localStorage.setItem('formData', name); }});Copy the code

Eslint-plugin-react-hooks plugin eslint-plugin-react-hooks plugin eslint-plugin-react-hooks plugin eslint-plugin-react-hooks plugin

Customize the Hook

A custom Hook is more like a convention where functions must be named starting with use.

A custom Hook is the abstraction of the logic shared between two function components.

Here’s an example:

Component 1: Displays the online status of friends

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

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

  if (isOnline === null) {
    return 'Loading... ';
  }
  return isOnline ? 'Online' : 'Offline';
}
Copy the code

Component 2: The chat application has a list of contacts that need to be set to green when the user is online

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

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

  return (
    <li style={{ color: isOnline ? 'green: 'black' }}>
      {props.friend.name}
    </li>
  );
}
Copy the code

Extract custom Hook, return friend online status Boolean

import { useState, useEffect } from 'react';

function useFriendStatus(friendID{
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() = > {
    function handleStatusChange(status{
      setIsOnline(status.isOnline);
    }

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

  return isOnline;
}
Copy the code

Use custom hooks in component one and component two, respectively

Component 1 using custom Hook:

function FriendStatus(props{
  const isOnline = useFriendStatus(props.friend.id);

  if (isOnline === null) {
    return 'Loading... ';
  }
  return isOnline ? 'Online' : 'Offline';
}
Copy the code

Component two uses custom hooks

function FriendListItem(props{
  const isOnline = useFriendStatus(props.friend.id);

  return (
    <li style={{ color: isOnline ? 'green: 'black' }}>
      {props.friend.name}
    </li>
  );
}
Copy the code

The logical clarity of the code is obvious.

Hook API index

In general, useState and useEffect can meet our requirements. All hooks are attached here, and business scenarios can be sent to the official website for study.

  • Based on the hooks

    • useState
    • useEffect
    • useContext
  • Additional hooks

    • useReducer
    • useCallback
    • useMemo
    • useRef
    • useImperativeHandle
    • useLayoutEffect
    • useDebugValue

conclusion

The above examples and some terms can be referred to the official document of React for beginners to learn. I am also a React novice. I will output the Basic series of React while learning and grow with everyone.