React 16.8 Hook is a new feature that is more like functional programming. It uses function declaration instead of class declaration. There is no need to write declaration cycles and render functions like class declaration components

A: useContext:

Core function: to solve the father-child components between the value

Let’s review some common ways to pass values

1. The props and value:

The data is passed top-down (from the parent and child) through the props property, which is cumbersome to pass layer by layer in the component tree

import React, { Component } from 'react'
class Father extends Component {
    render(){
        return(
            <Son value='dark' />)}}function Son(props) {
    return (
        <div>
            < GrandChild value={props.value} />
        </div>
    );
}

class GrandChild extends Component {
    render() {
        return <div>{this.props.value}</div>}}export default Father

Copy the code

2. The Context and value:

Context provides a way to pass values deep into the component tree without manually adding props to each layer of the component, avoiding the need to pass props through layers of intermediate elements

Create a Context object. When React renders a component subscribed to the Context object, the component reads the current Context value from the closest matching Provider in the component tree.

The defaultValue parameter takes effect only if the component does not match the Provider in the tree

import React, { Component } from 'react'

const ThemeContext = React.createContext('light');
class Context extends Component {
    render(){
        return(
            <ThemeContext.Provider value='dark'>
                <Toolbar />
            </ThemeContext.Provider>)}}function Toolbar() {
    return (
        <div>
            <ThemedButton />
        </div>
    );
}

class ThemedButton extends Component {
    render() {
        return(
            <ThemeContext.Consumer>
                {(value) => (
                    <div>{value}</div>
                 )}
            </ThemeContext.Consumer>)}}export default Context
Copy the code

3. UseContext values

UseContext makes it easy to subscribe to changes to the context, read the value of the context and render it on the component. For example, with useContext, you still need to use < myContext. Provider> in the upper component tree to provide Context for the lower component.

Receives a context object (the return value of React. CreateContext) and returns the current value of the context. The current context value is determined by the < MyContext.provider > value prop of the upper-layer component closest to the current component.

const MyContext = React.createContext(defaultValue);
const value = useContext(MyContext); The useContext argument must be the context object itself
import React , {useContext , createContext } from 'react'
const CountContext = createContext(0)

function UseContext() {
    return(
        <div>
            <CountContext.Provider value={2}>
            <Counter />
            </CountContext.Provider>
        </div>)}function Counter(){
    let count = useContext(CountContext);
    return(
        <h2>{count}</h2>)}export default UseContext
Copy the code

If you’re already familiar with the Context API before you hit the Hook, it should make sense, UseContext (MyContext) is equivalent to static contextType = MyContext or < myContext.consumer > in the class component.

2: userReducer

const [state, dispatch] = useReducer(reducer, initialArg, init);

An alternative to useState. It receives a Reducer of the form (state, action) => newState and returns the current state and its accompanying dispatch method. (If you’re familiar with Redux, you already know how it works.)

1. How Redux works

One of the core ideas of Redux is to put state into a unique global object (usually called a Store), and to modify state, call the corresponding Reducer function to update the state in the Store, something like this:

The figure above depicts the process by which component A changes the states in B and C:

  • When the three components are mounted, the corresponding state data is fetched and subscribed from the Store and displayed (note that it is read-only and cannot be modified directly).
  • The user clicks component A to trigger the event listener function
  • The actions corresponding to Dispatch in the listener function are passed into the Reducer function
  • The Reducer function returns the updated state and updates the Store with it
  • Since components B and C subscribe to the Store state, they re-fetch the updated state and adjust the UI

Reducer for example

function countReducer(state,action){
    switch(action.type){
        case 'add':
           return state+1
        case 'sub':
            return state-1
        default:
            return state
        }
}
Copy the code

2. How to use useReducer

const [state, dispatch] = useReducer(reducer, initialArg, init)

  1. The first reducer parameter is obviously required and has exactly the same form as the Reducer function in Redux, that is (state, action) => newState.
  2. The second parameter, initialArg, is the initial value of the state.
import { useReducer } from "react";
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 UseReducer() {
    const [state, dispatch] = useReducer(reducer, initialState);
    return (
        <>
          <div>count:{state.count}</div>
            <button onClick={()= > dispatch({type: 'decrement'})}>-</button>
            <button onClick={()= > dispatch({type: 'increment'})}>+</button>

        </>
     );
}

export default UseReducer
Copy the code

3. The third parameter init is an optional function for Lazy Initialization, in which case the initial state is set to init(initialArg). This also facilitates future actions that reset state:

import { useReducer } from "react";

function init(initialCount) {
    return {
        count: initialCount
    };
}

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

function UseReducer() {
    const [state, dispatch] = useReducer(reducer, 0, init);
    return (
      <>
        <div>count:{state.count}</div>
           <button onClick={()= >Dispatch ({type: 'decrement'})} ></button>
           <button onClick={()= >Dispatch ({type: "increment"})} ></button>
           <button onClick={()= >Dispatch ({type: 'reset'})} > reduction</button>
     </>
   );
}

export default UseReducer
Copy the code

In fact, it is a simple read value and change value, in fact, with useState can be done in one line of code

3. When should you use useReducer

UseReducer and useState are used for much the same purpose: to define state and modify state logic. UseReducer can be tedious to use, but if your state management has at least one of the following problems:

  • The states that need to be maintained are complex and depend on each other
  • The process of changing the status is complicated