The origin of the Hooks

React Hooks are another groundbreaking new feature introduced from V16.8 that allows us to use state and other React features without writing a class.

Hooks were introduced to solve a long-standing problem with React:

  • Logic between components is difficult to reuse:

React does not provide a way to attach reusable logic to components. To address this reuse problem, design patterns such as higher-order components (such as the Connect method in Redux) or render props were introduced. This often requires modification of the structure of components, which is very troublesome.

  • Complex components are difficult to understand

React provides a number of lifecycle functions, but typically a lot of the business logic needs to be written in different lifecycle functions, such as listening for data in componentDidMount and unlistening for that data in componentWillUnmount. Multiple business logic can exist simultaneously within a lifecycle function. All of this makes our components complex and difficult to understand.

  • JavaScript class flaws

The this reference in JavaScript is determined at run time, unlike in other object-oriented languages. React also has the concepts of class component and function component, which component should be used when it is confusing. In terms of code optimization, Class Component is much harder to precompile and compress than normal functions.

Hooks features

  • Completely optional.
  • 100% backward compatibility. Using Hooks does not affect previous code functionality.
  • Now available. Hooks have been released on React V16.8.0.

State Hooks

Using Hooks allows us to convert from class Component to function Component without preventing us from using other react features. Let’s write a simple example

import React, { useState } from 'react'; Const [count, setCount] = useState(0); 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

The original class component is written as:

class Example extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } 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

The Hooks do the same thing, but are written more succinctly. Next, we learn about a State Hooks — useState

Use the useState Hooks to add some internal state data inside the component. Usage:

const [count, setCount] = useState(0);
Copy the code

The useState function takes only the initial value of the created state and returns the current state and the function that updated the state. What does the above code execution do? It creates a state variable — count (which can be declared by any name), takes the passed argument 0 as the initial value of count, and returns a function to change count — setCount (the function name here can also be named by any name). If we need to use count in a page presentation or logic, we can use count directly (instead of this.state.count) to access the value of count normally; If we need to change the value of count in state, we can execute the following code:

SetCount (count + 1)Copy the code

Equivalent to (take our usual setState notation as follows) :

Enclosing setState (this) state) count + 1)Copy the code

In other words, when we call setCount, React helps us implement this.setstate (), which changes the value of count in state.

Here, when we call useState, why do we return the value as an array? This involves array deconstruction in ES6, because useState returns an array whose first entry is the state variable, and whose first variable is the function that changes state. Equivalent to the following code:

var countStateVariable = useState(0); Var count = countStateVariable[0]; Var setCount = countStateVariable[1]; // Second value in the arrayCopy the code

Effect Hooks

Effect Hook allows you to perform side effects in function components, such as network requests, subscribing to a module, or DOM operations. Common side effects in React are divided into those that need to be removed and those that do not.

Effect that does not need to be cleaned

Sometimes we need to do things after DOM updates, such as sending requests, changing the DOM, and logging, which are common operations that don’t need to be cleaned up. Using the counter example above, add a small feature: Set the title of the document to a message containing the number of clicks.

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

The useEffect Hook tells the React component what to do after each rendering. React saves the function you passed (we’ll call it “effect”) and calls it after a DOM update. Here we tell React to set the title of the document to the number of clicks after each render. UseEffect {componentDidMount; componentDidUpdate;} useEffect {componentDidMount;} You only have to write it once.

Effects that need to be cleared

Side effects such as subscribing to external data need to be removed to prevent memory leaks.

In React Class, we usually subscribe to data in componentDidMount, and we also need to clear subscriptions in componentWillUnmount, so the logic of subscribe and clear subscriptions is split up by these lifecycle functions.

So how to use Hook to achieve this function? You might think that we would need one useEffect for subscribing data and another useEffect for cleaning. But because of the tightness between adding and removing subscriptions, useEffect is designed so that these closely related logic can be executed in the same place: if your Effect returns a function, React will call it when a cleanup operation is performed. The above adding and removing subscriptions can be written as:

useEffect(() => { function handleStatusChange(status) { setIsOnline(status.isOnline); } / / subscription data ChatAPI. SubscribeToFriendStatus (props. Friend. Id, handleStatusChange); // return function, Contains clear subscription data operation return function the cleanup () {ChatAPI. UnsubscribeFromFriendStatus (props. Friend. Id, handleStatusChange); }; });Copy the code

When does effect perform a clean operation? React performs cleanup operations when components are uninstalled.

If we feel that executing effect once every render will cost performance, we can also set it: If a particular value does not change between renders, React can skip the call to Effect by passing an array as the second optional argument to useEffect. React will determine whether effect is executed based on whether the argument changes.

useEffect(() => { document.title = `You clicked ${count} times`; }, [count]); // Update only when count changesCopy the code

At this point, we pass [count] as the second argument. If count=5 and does not change when the component is re-rendered, React will compare the previous rendering [5] of the component to the subsequent rendering [5]. React skips this effect and optimizes performance. If all elements in the array are equal (5 === 5), React skips this effect.

According to the above principle, if we want effect to be executed once, that is, when the component is mounted and unmounted, we can pass an empty data ([]) as the second parameter. Since we pass an empty array, the result will remain the same every time we render the comparison. This tells React that this effect never needs to be executed again.

conclusion

Remember remember that remember remember Hooks *useState * and UseEffect. Hooks allow us to use state and other React features in function components, eliminate cumbersome lifecycle functions, and allow us to set multiple effects to particles with complete logic, making code logic clearer. In the meantime, Hooks have more apis to explore