No, no, it’s 2021. There’s no one who can’t React Hooks!

Thoughts and usage in order to study the React Hooks, to arrange the notes, after watching, even for the React of Hooks a primer ~ thought and basic usage

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

Function Component 🆚 Class Component

React is all about components. Before v16.8, the standard way to write components was class. After V16.8, function-based hooks were added.

Any component can be written as a class or as a hook. Below is a comparison of a class component (left) and a function component (right). For complex components, the difference is even greater.

As you can see, function components are more concise, have less code, and are “light” to use, while class components are “heavy.”

Redux author Dan Abramov summed up several shortcomings of component classes:

  • Large components are hard to break down, refactor, and test.
  • The business logic is scattered among the various methods of the component, resulting in repetitive or relational logic.
  • Component classes introduce complex programming patterns, such as render props and higher-order components

🤔 Differences between classes and functions

Strictly speaking, a class component is different from a function component. Different writing methods represent different programming methodologies.

A class is an encapsulation of data and logic. That is, the state and operation methods of a component are encapsulated together. If you choose a class, you should write all the relevant data and operations in the same class.

In general, a function should only do one thing, and that is return a value. If you have multiple operations, each operation should be written as a separate function. Furthermore, the state of the data should be separated from the method of operation. According to this philosophy, the React function component should only do one thing: return the component’s HTML code, and nothing else.

React has long supported function components. Here’s an example.

function Welcome(props) {
    return <h1>hello,{props.name}</h1>
}
Copy the code

This function does only one thing: it returns the HTML code of the component based on the input parameters. Such functions, which only perform pure data calculations (conversions), are called “pure functions” in functional programming.

However, this approach has major limitations in that it cannot include state and does not support lifecycle methods, so it is not a substitute for classes.

React Hooks are designed to enhance function components so that they can write a fully functional component without using “classes” at all.

If pure functions can only evaluate data, where do they write operations that don’t involve computation (such as logging, storing data, changing application state, and so on)?

Functional programming refers to operations that have nothing to do with the calculation of data as “side effects”. A function is no longer pure if it contains operations that produce side effects, and we call it impure.

The interior of a pure function can contain side effects only by indirect means (that is, through other function calls).

Hook

The word Hook means “Hook”.

React Hooks mean that components should be written as pure functions, and if external functions and side effects are needed, use Hooks to “hook” them. So hooks are a side-effect solution to the React function component.

Use whatever hooks you need. React provides some common hooks by default, but you can also encapsulate your own.

All hooks introduce external functions to functions. Therefore, the React convention uses the use prefix to name hooks for easy identification. You want to use the XXX function and name the hook usexxx.

Here are the four most common React hooks provided by default:

  • useState()
  • useContext()
  • useReducer()
  • useEffect()

UseState () : status hook

UseState () is used to introduce state to function components. Pure functions cannot have state, so put the state inside the hook.

When the user clicks a button, the text of the button changes, depending on whether the user clicks, which is the state.

import React, { useState } from "react";

export default function  Button()  {
  const  [buttonText, setButtonText] =  useState("Click me, please");

  function handleClick()  {
    return setButtonText("Thanks, been clicked!");
  }

  return  <button  onClick={handleClick}>{buttonText}</button>;
}
Copy the code

In the code above, the Button component is a function that uses the useState() hook internally to introduce state.

The useState() function takes the initial value of the state as an argument, which in this case is the text of the button. This function returns an array whose first member is a variable (buttonText, in this example) that points to the current value of the state. The second member is a function that updates the state by prefixing the set with the variable name of the state (in this example, setButtonText).

UseContext () : Shared state hook

If you need to share state between components, use useContext().

We now have two components, Navbar and Messages, and we want to share state between them.

<div className="App">
  <Navbar/>
  <Messages/>
</div>
Copy the code

The first step is to create a Context outside the component using the React Context API.

const AppContext = React.createContext({})
Copy the code

The component encapsulation code is as follows. Appcontext. Provider provides a Context object that can be shared by quilt components.

<AppContext.Provider value={{
  username: 'superawesome'}} ><div className="App">
    <Navbar/>
    <Messages/>
  </div>
</AppContext.Provider>
Copy the code

The code for the Navbar component is as follows. The useContext() hook function is used to import the Context object from which the username property is retrieved.

const Navbar = () = > {
  const { username } = useContext(AppContext);
  
  return (
    <div className="navbar">
      <p>AwesomeSite</p>
      <p>{username}</p>
    </div>
  );
}
Copy the code

The code for the Message component is similar.

const Messages = () = > {
  const { username } = useContext(AppContext)

  return (
    <div className="messages">
      <h1>Messages</h1>
      <p>1 message for {username}</p>
      <p className="message">useContext is awesome!</p>
    </div>)}Copy the code

UseReducer () : Action hook

React itself does not provide state management, and external libraries are usually required. The most commonly used library for this is Redux.

The core concept of Redux is that components emit actions to communicate with the state manager. After the state manager receives the action, the Reducer function is used to calculate the newState. The Reducer function is in the form (state, action) => newState.

The useReducers() hook is used to introduce the Reducer function.

const [state, dispatch] = useReducer(reducer, initialState);
Copy the code

The above is the basic use of useReducer(), which takes the Reducer function and the initial value of the state as arguments and returns an array. The first member of the array is the current value of the state, and the second member is the dispatch function that sends the action.

Here is an example of a counter. The Reducer function used to calculate the state is as follows.

const myReducer = (state, action) = > {
  switch(action.type)  {
    case('countUp') :return  {
        ...state,
        count: state.count + 1
      }
    default:
      returnstate; }}Copy the code

The component code is as follows.

function App() {
  const [state, dispatch] = useReducer(myReducer, { count:   0 });
  return  (
    <div className="App">
      <button onClick={()= > dispatch({ type: 'countUp' })}>
        +1
      </button>
      <p>Count: {state.count}</p>
    </div>
  );
}
Copy the code

Because Hooks can provide shared state and Reducer functions, it can replace Redux in these areas. However, it doesn’t provide middleware or time travel, so if you need those, use Redux.

UseEffect () : Side effect hook

UseEffect () is a generic side effect hook. It can be used when no corresponding hook can be found. The most common is to request data from the server. The code that was previously placed in componentDidMount can now be placed in useEffect().

UseEffect () specifies a side effect function that is automatically executed every time a component is rendered. The side effects function is also executed after the component is first loaded in the WEB DOM.

UseEffect () is used as follows.

useEffect(()  =>  {
  // Async Action
}, [dependencies])
Copy the code

UseEffect () takes two arguments. The first argument is a function in which the code for asynchronous operations is placed. The second argument is an array that gives the Effect dependencies, and useEffect() is executed whenever this array changes. The second argument can be omitted, and useEffect() is executed each time the component is rendered.

If the second argument is an empty array, then the side effect argument does not have any dependencies. Therefore, the side effects function is executed only once after the component is loaded into the DOM, and not again after the component is re-rendered. This makes sense, because side effects do not depend on any variables, so no matter how those variables change, the result of the side effect function will not change, so run once is enough.

Any side effect can be introduced using useEffect(). Its common uses are as follows.

  • Fetching Data Fetching
  • Setting up a subscription
  • Changing the DOM
  • Logging output

Let’s look at an example.

const Person = ({ personId }) = > {
  const [loading, setLoading] = useState(true);
  const [person, setPerson] = useState({});

  useEffect(() = > {
    setLoading(true); 
    fetch(`https://swapi.co/api/people/${personId}/ `)
      .then(response= > response.json())
      .then(data= > {
        setPerson(data);
        setLoading(false);
      });
  }, [personId])

  if (loading === true) {
    return <p>Loading ...</p>
  }

  return <div>
    <p>You're viewing: {person.name}</p>
    <p>Height: {person.height}</p>
    <p>Mass: {person.mass}</p>
  </div>
}
Copy the code

In the above code, useEffect() is executed whenever the component parameter personId changes. UseEffect () is also executed when the component is first rendered.

There is one caveat when using useEffect(). If there are multiple side effects, multiple useeffects () should be called rather than written together.

UseEffect () return value

Side effects occur as components are loaded, and may need to be cleaned up when components are unloaded.

UseEffect () allows you to return a function that is executed to clean up side effects when the component is unloaded. UseEffect () does not return any value if no side effects need to be cleaned up.

useEffect(() = > {
  const subscription = props.source.subscribe();
  return () = > {
    subscription.unsubscribe();
  };
}, [props.source]);
Copy the code

In the example above, useEffect() subscribes to an event when the component is loaded and returns a cleanup function that unsubscribes when the component is unloaded.

In practice, since side effects are executed every render by default, the cleanup function is executed not only once when the component is unloaded, but also once every time the side effects function is re-executed to clean up the side effects of the previous render.

Create your own Hooks

The Hooks code from the above example can also be wrapped into a custom Hook for easy sharing.

const usePerson = (personId) = > {
  const [loading, setLoading] = useState(true);
  const [person, setPerson] = useState({});
  useEffect(() = > {
    setLoading(true);
    fetch(`https://swapi.co/api/people/${personId}/ `)
      .then(response= > response.json())
      .then(data= > {
        setPerson(data);
        setLoading(false);
      });
  }, [personId]);  
  return [loading, person];
};
Copy the code

In the code above, usePerson() is a custom Hook.

The Person component uses this new hook instead, introducing encapsulation logic.

const Person = ({ personId }) = > {
  const [loading, person] = usePerson(personId);

  if (loading === true) {
    return <p>Loading ...</p>;
  }

  return (
    <div>
      <p>You're viewing: {person.name}</p>
      <p>Height: {person.height}</p>
      <p>Mass: {person.mass}</p>
    </div>
  );
};
Copy the code

📎 reference

The official documentation

Learn React hooks easily: useEffect() as an example

React Hooks tutorial

The last

🥺 if there is a problem, please big guy correct ~

🥺 if helpful, I hope to be able to like the comment collection ~