useState, useContext, useReducer, useEffect hooks commonly used in React Hooks

Posted by FireyIce01 on Mon, 23 Sep 2019 12:34:45 +0200

React is the mainstream front-end framework. Version v16.8 introduces a new API called React Hooks, which overturns previous usage.

I. Disadvantages of class Components

class Component Writing

import React, { Component } from "react";
export default class Button extends Component {
  constructor() {
    super();
    this.state = { buttonText: "Click me, please" };
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState(() => {
      return { buttonText: "Thanks, been clicked!" };
    });
  }
  render() {
    const { buttonText } = this.state;
    return <button onClick={this.handleClick}>{buttonText}</button>;
  }
}

This component class is just a button, but as you can see, its code is already "heavy". The real React App consists of several classes, one by one, and the complexity increases exponentially. Adding Redux makes it more complex.

Dan Abramov, author of Redux, summarizes several shortcomings of component classes.

  1. Large components are difficult to split and reconstruct and to test.
  2. Business logic is dispersed among the methods of components, leading to duplicate logic or association logic.
  3. Component classes introduce complex programming patterns, such as render props and higher-order components.

II. Functional Components

The React team wants components not to become complex containers, but rather just pipelines for data streams. Developers can assemble pipelines according to their needs. Components should be best written in terms of functions, not classes.

React has long supported functional components, and here's an example.

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

However, there are significant limitations in this way of writing. It must be a pure function, it cannot contain states, it does not support lifecycle methods, and therefore it cannot replace classes.

React Hooks is designed to enhance version function components, without using "classes" at all, can write a full-featured component.

3. The Meaning of Hook

The word Hook means "hook".

React Hooks means that components are written as pure functions as possible, and if external functions and side effects are required, external code is "hooked" in with hooks. React Hooks are the hooks.

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

All hooks introduce external functions for functions, so React stipulates that hooks are named with use prefix for easy identification. If you want to use the xxx function, the hook is named usexxx.

Here are four of the most commonly used hooks that React provides by default.

  1. useState()
  2. useContext()
  3. useReducer()
  4. useEffect()

4. useState(): status hook

useState() is used to introduce state for function components. Pure functions can't have states, so put states in hooks.

The component class in front of this article, when the user clicks the button, the text of the button will change. The text depends on whether the user clicks or not. This is the state. Use useState() to rewrite as follows.

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>;
}

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

The function useState() accepts the initial value of the state as a parameter, and the initial value of the example above is the text of the button. This function returns an array. The first member of the array is a variable (buttonText in the above example), which points to the current value of the state. The second member is a function that updates the state, and the Convention is to prefix the set with the variable name of the state (in the case of setButtonText).

5. useContext(): Shared status hook

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

Now there are two components, Navbar and Mesages, which we want to share state with.

//The first step is to use the React Context API to create a Context outside the component.
const AppContext = React.createContext({});
//The code for the Navbar component is as follows.
const Navbar = () => {
  const { username } = useContext(AppContext)

  return (
    <div className="navbar">
      <p>AwesomeSite</p>
      <p>{username}</p>
    </div>
  )
}
//In the code above, the useContext() hook function is used to introduce the Context object from which to obtain the username attribute.
//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>
  )
}
//Component encapsulation code is as follows.
function App() {
  return (
    <AppContext.Provider value={{
      username: 'superawesome'
    }}>
      <div className="App">
        <Navbar />
        <Messages />
      </div>
    </AppContext.Provider>
  );
}
//In the code above, AppContext.Provider provides a Context object that can be shared by subcomponents.

6. useReducer(): action hook

eact itself does not provide state management functions, and usually requires the use of external libraries. The most common library in this area is Redux.

The core concept of Redux is that components emit actions to communicate with state management communication. After the state manager receives the action, it uses the Reducer function to calculate the new state. The form of the Reducer function is (state, action) => new state.

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

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

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>
  );
}
//The above is the basic use of useReducer(), which takes the initial value of the Reducer function and state as parameters 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.
 

useEffect(): Side effect hook

useEffect() is used to introduce operations with side effects, the most common of which is to request data from the server. Previously, the code in CompoonentDidMount can now be placed in useEffect().

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]);

//In the above usage, useEffect() takes two parameters. The first parameter is a function in which the code for asynchronous operations is placed. The second parameter is an array that gives Effect dependencies, and useEffect() executes whenever the array changes. The second parameter can be omitted, where useEffect() is executed every time the component is rendered.
  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>
  );
};

function App() {
  const [show, setShow] = useState("1");

  return (
    <div className="App">
      <Person personId={show} />
      <div>
        Show:
        <button onClick={() => setShow("1")}>Luke</button>
        <button onClick={() => setShow("2")}>C-3PO</button>
      </div>
    </div>
  );
}
//In the above code, useEffect() is executed whenever the component parameter personId changes. useEffect() is also executed when the component is first rendered.

8. Create your own Hooks

The above Hooks code can also be encapsulated into a custom Hooks 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];
};
//In the code above, usePerson() is a custom Hook.

//The Person component uses this new hook to introduce 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>
  );
};

function App() {
  const [show, setShow] = useState("1");

  return (
    <div className="App">
      <Person personId={show} />
      <div>
        Show:
        <button onClick={() => setShow("1")}>Luke</button>
        <button onClick={() => setShow("2")}>C-3PO</button>
      </div>
    </div>
  );
}

Topics: React JSON Programming Attribute