[Front-end knowledge] React foundation consolidation (forty-four) - other Hooks (useContext, useReducer, useCallback)

React foundation consolidation (forty-four) - other Hooks (useContext, useReducer, useCallback)

1. The use of useContext

When developing class components, we use 类名.contextType = MyContextthe method to obtain context in the class, multiple contexts or MyContext.Consumershare context in functional components:

import React, {
    
     memo } from 'react'
import {
    
     UserContext, ThemeContext } from './context'

export default memo(function App() {
    
    

// 使用Context

  return (
    <div>
      <UserContext.Consumer>
        {
    
    
          value => {
    
    
            return (
              <h2>
                <ThemeContext.Consumer>
                  {
    
    
                    value => {
    
    
                      <span></span>
                    }
                  }
                </ThemeContext.Consumer>
              </h2>
            )
          }
        }
      </UserContext.Consumer>
    </div>
  )
})

It can be seen that when we need to use multiple Contexts, there are a lot of cumbersome nested codes; and Context Hook allows us to directly obtain the value of a Context through Hook, as follows:

import React, {
    
     memo, useContext } from "react";
import {
    
     ThemeContext, UserContext } from "./context";

export default memo(function App() {
    
    
  // 使用Context
  const user = useContext(UserContext);
  const theme = useContext(ThemeContext);

  return (
    <div>
      <h2>
        User: {
    
    user.name} - {
    
    user.age}
      </h2>
      <h2>
        Theme: {
    
    theme.color} - {
    
    theme.size}
      </h2>
    </div>
  );
});

It can be seen that Context Hook only uses two lines of code to replace the complicated nested code above, which is very efficient and concise.

Second, the use of useReducer

useReducer is an alternative to useState. When the state processing logic is complex, you can use useReducer to split it, or you can use useReducer when you need to rely on the previous state when modifying the state.

There are very few scenarios used by useReducer, and it is usually used in scenarios that require unified management and modification of multiple data. For example, when we need to process multiple data in a unified manner, if we use useState, we need to define it multiple times, and the reducer can define and modify it uniformly:

import React, {
    
     memo, useReducer, useState } from "react";

function reducer(state, action) {
    
    
  switch (action.type) {
    
    
    case "increment":
      return {
    
     ...state, counter: state.counter + 1 };
    case "decrement":
      return {
    
     ...state, counter: state.counter - 1 };
    case "add_number":
      return {
    
     ...state, counter: state.counter + action.num };
    case "sub_number":
      return {
    
     ...state, counter: state.counter - action.num };
    default:
      return state;
  }
}

export default memo(function App() {
    
    
  // const [count, setCount] = useState(0);
  // const [user, setUser] = useState(0);
  // const [list, setList] = useState(0);

  const [state, dispatch] = useReducer(reducer, {
    
    
    counter: 0,
    user: {
    
    },
    list: [],
  });

  return (
    <div>
      {
    
    /* <h2>当前计数:{count}</h2>
      <button onClick={(e) => setCount(count + 1)}>+1</button>
      <button onClick={(e) => setCount(count - 1)}>-1</button>
      <button onClick={(e) => setCount(count + 5)}>+5</button>
      <button onClick={(e) => setCount(count - 5)}>-5</button>
      <button onClick={(e) => setCount(count + 100)}>+100</button> */}

      <h2>当前计数:{
    
    state.counter}</h2>
      <button onClick={
    
    (e) => dispatch({
    
     type: "increment" })}>+1</button>
      <button onClick={
    
    (e) => dispatch({
    
     type: "decrement" })}>-1</button>
      <button onClick={
    
    (e) => dispatch({
    
     type: "add_number", num: 5 })}>
        +5
      </button>
      <button onClick={
    
    (e) => dispatch({
    
     type: "sub_number", num: 5 })}>
        -5
      </button>
      <button onClick={
    
    (e) => dispatch({
    
     type: "add_number", num: 100 })}>
        +100
      </button>
    </div>
  );
});

3. Use of useCallback

The actual purpose of useCallback is for performance optimization. useCallback will return a memoized (memorized) value of a function. When the dependency remains unchanged, the returned value is the same when it is defined multiple times.

Performance optimization of useCallback:

  1. When a function needs to be passed to a subcomponent, useCallback can be used for optimization, and the optimized function can be passed to the subcomponent

    import React, {
          
           memo, useCallback, useState } from "react";
    
    const HYIncrement = memo(function (props) {
          
          
      const {
          
           increment } = props;
    
      console.log("HYIncrement被渲染");
    
      return (
        <div>
          <button onClick={
          
          increment}>increment + 1</button>
        </div>
      );
    });
    
    export default memo(function App() {
          
          
      const [count, setCount] = useState(0);
      const [message, setMessage] = useState("hello");
    
      // 使用useCallback
      const increment = useCallback(
        function () {
          
          
          setCount(count + 1);
        },
        [count]
      );
    
      // 普通函数
      // const increment = () => {
          
          
      //   setCount(count + 1);
      // };
    
      return (
        <div>
          <h2>计数:{
          
          count}</h2>
          <button onClick={
          
          increment}>+1</button>
    
          <HYIncrement increment={
          
          increment} />
    
          <h2>message:{
          
          message}</h2>
          <button onClick={
          
          (e) => setMessage("world")}>修改 message</button>
        </div>
      );
    });
    
    
  2. advanced optimization

    When count changes, also use the same function

      // 做法一:将count依赖移除掉,缺点:存在闭包陷阱,不依赖count后setCount每次拿到的count并非最新的count
      // const increment = useCallback(function foo() {
          
          
      //   console.log("increment");
      //   setCount(count + 1);
      // }, []);
    
      // 做法二:利用useRef,在组件多次渲染时,返回同一个值
      const countRef = useRef();
      countRef.current = count;
      const increment = useCallback(
        function foo() {
          
          
          console.log("increment");
          setCount(countRef.current + 1);
        },
        []
      );
    

Guess you like

Origin blog.csdn.net/weixin_42919342/article/details/132051382