Before we get started, here’s a picture:

React Hooks?

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

To summarize this inaccurately, the React team wants developers to use less class components and more function components.

This begs the question: what’s wrong with class components? What’s so good about function components?

Disadvantages of class components

In my opinion, component classes have several problems:

  • Heavy lifting: Large components are hard to break down and refactor, and hard to test.
  • Logic fragmentation: Business logic is scattered across the components’ methods, resulting in duplicate or relational logic.
  • Hard to reuse: Complex programming patterns such as render props and higher-order components are introduced to achieve reuse on top of class components.

The React team wanted to:

Components do not become complex containers, but rather pipes for data flow. Developers can assemble pipes as needed.

A component is best written as a function, not a class.

Start with implementing an in-component request…

Next, I’ll try to illustrate the difference between a class component and a function component by implementing an intra-component request.

In the class component, if we want to implement the request, we do this:

import React from 'react';

class Component extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      loading: false.info: null}; } componentDidMount() {this.fetchInfo();
  }

  fetchInfo = async() = > {this.setState({ loading: true });
    const info = await getInfo();
    this.setState({
      info,
      loading: false}); } render() {const { info } = this.state;
    return <div>{info}</div>; }}export default Component;

Copy the code

Problem 1: Logic dispersion

As a simple request within a component, the business logic is scattered among the four methods of the component.

  • constructor
    • The state initialization
  • componentDidMount
    • Execute request method
  • fetchInfo
    • Initiate requests and process data
  • render
    • Returns content based on status

As components are pieced together, it is easy to duplicate logic or link logic if developers are negligent.

Problem 2: Hard to break down and refactor, and hard to test

In the code above, the request logic is strongly coupled to the component lifecycle, and the code is placed in three React lifecycle hook functions.

As components grow larger, a componentDidMount can be dozens or even hundreds of rows long enough to decouple, split, and refactor.

Problem 3: Introducing new features is cumbersome and not easy enough for developers

If we want to add a loading state, we must:

  • In constructor, declare a loading in this.state
  • Add state handling to Loading in fetchInfo
  • Make a special judgment about loading in render

What if I also want to do “parsed parameters, dependency handling, global configuration, request data logic, callback handling, loop requests, cache handling” and so on?

Pretty boy speechless.

Problem 4: Hard to reuse

The code above is so lifecycle specific that it is difficult to abstract it out. For the purpose of abstraction, we can only resort to complex programming patterns such as render props and HOC.

How do you use react hooks?

Simple version:

import { useState, useEffect } from 'react';

const Component = (a)= > {
  const [ loading, setLoading ] = useState(false);
  const [ info, setInfo ] = useState(' ');

  useEffect((a)= > {
    setLoading(true);
    const info = await getInfo();
    setLoading(false); setInfo(info); } []);if (loading) return <div>In the loading...</div>;
  return <div>{info}</div>
}

export default Component;
Copy the code

But remember, the most important power of Hooks is logic reuse! We can encapsulate all this logic!

The advanced version:

import { useState, useEffect } from 'react';

function useInfo() {
  const [ loading, setLoading ] = useState(false);
  const [ info, setInfo ] = useState(' ');

  useEffect((a)= > {
    setLoading(true);
    const info = await getInfo();
    setLoading(false); setInfo(info); } []);return { loading, info };
}

const Component = (a)= > {
  const { info, loading } = useInfo();

  if (loading) return <div>In the loading...</div>;
  return <div>{info}</div>
}

export default Component;
Copy the code

Oh my God, the request method is abstracted! It (useInfo) can be reused as a general logic!

All the request-related processing logic is placed here in userInfo.

Its benefits are obvious:

  • It’s cheap to learn, and you know what your code is doing at a glance
  • Business logic centralization, everything is in useInfo
  • You can reuse it, just take useInfo out and run around

Code organization complexity comparison: Class components vs. functional components

What apis do React Hooks have? What are they for?

React Hooks mean that components should be written as pure functions, and if external functions and side effects are needed, use Hooks to “hook” external code.

Some features of a function component

Before getting into the API, I’d like to tell you about some of the features of function components so you can understand them:

  • Each time the state and props change, the props is re-executed.
  • UseXXX in a function component is created only once;
  • UseEffect is executed only after the function runs and returns a new JSX. UseEffect is equivalent to componentDidXXX.

When you don’t understand the following API, look back at these features of the function component to help you understand them better.

UseState () : status hook

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

import React, { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  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 above code is equivalent to:

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

UseContext () : Shared state hook

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

const themes = {
  light: {
    foreground: "# 000000".background: "#eeeeee"
  },
  dark: {
    foreground: "#ffffff".background: "# 222222"}};const ThemeContext = React.createContext(themes.light);

function App() {
  return (
    <ThemeContext.Provider value={themes.dark}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar(props) {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

function ThemedButton() {
  const theme = useContext(ThemeContext);

  return (
    <button style={{ background: theme.background.color: theme.foreground}} >
      I am styled by theme context!
    </button>
  );
}
Copy the code

UseReducer () : Action hook

The useReducers() hook is used to introduce Reducer capabilities similar to those in Redux (incomplete).

const initialState = {count: 0};

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={()= > dispatch({type: 'decrement'})}>-</button>
      <button onClick={()= > dispatch({type: 'increment'})}>+</button>
    </>
  );
}
Copy the code

UseEffect () : Side effect hook

UseEffect () is used to introduce operations that have side effects, most commonly requesting data from the server. The code that was previously placed in componentDidMount can now be placed in useEffect().

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

function Example() {
  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 (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
Copy the code

The above code is equivalent to:

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

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

  componentDidUpdate() {
    document.title = `You clicked ${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

React Hooks: Why do they smell so good?

React Hooks are the trend in React development for the following reasons:

React Hooks provide developers with the ability to refine a feature. There are so many great libraries that users can solve a big problem with just one useXXX call.

Here’s an example:

In the community, there is a great request library based on React hooks: SWR. In this library, he solved all aspects of the request: parsing parameters, dependency handling, global configuration, request data logic, callback handling, loop requests, cache handling…

Imagine how difficult it would be to implement a class component that you want to reuse.

But after the React hooks came along, it was clear. We just need each API based on the React hooks, and once we’ve done what we need to do, wrap it all in one useSWR.

For developers, just say const {data, error} = useSWR(‘/ API /user’, fetcher) and you can use it all! It’s not too convenient! Logical focus and clear, write multiple reuse at a time, incense!

In addition, there are many excellent libraries in the community, such as:

Collection of React Hooks

awesome-react-hooks

@umijs/hooks

react-use

react-query – Hooks for fetching

They can greatly improve the efficiency of developers and are well worth knowing and using.