preface

The React component contains Hooks that are primarily used by function components. Function components have some functions that are really difficult to implement, such as lifecycle Hooks. Redux: Hooks are a function component that has the capabilities of class components. The use of Hooks brings us to another way of implementing components. I don’t think this is a concept, so don’t worry about it.

Tips: According to the convention, I am also an entry level player, the depth of the article will not reach the level of the master, only hope to be helpful to the entry level friends like me.

The text will be long, and only examples will make the most sense

Let’s start with a component that manages state in React

import React from 'react'

class Counter extends React.Component {
    state = {
        count: 0
    }

    componentDidMount() {
        this.interval = setInterval((a)= > {
            this.setState({
                count: this.state.count + 1})},1000);
    }

    componentWillUnmount() {
        if(this.interval) {
            clearInterval(this.interval)
        }
    }

    render() {
        return (
            <div>count is : {this.state.count}</div>)}}export default Counter;
Copy the code

This code writes a simple counter component that manages a count state (that is, a piece of data named count), executes the timer after the component is loaded, increases the count state by 1 per second, and clears the timer before the component is unloaded. This is done by adding and uninstalling timers via lifecycle Hooks. Function components could not use lifecycle functions until Hooks were introduced, so state management would not be possible.

Hooks are introduced to enable state management for function components as well

Start with a couple of Hooks, which will be covered in more detail below

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

function CounterFunc() {
    const [count, setCount] = useState(0)

    useEffect((a)= > {
        const interval = setInterval((a)= > {
            setCount(c= > c + 1)},1000)

        return (a)= > clearInterval(interval)
    },[])

    return (
        <div>count is : {count}</div>)}export default CounterFunc;
Copy the code

Here is a piece of code that introduces two functions at the beginning :useState and useEffect.

In the function component CounterFunc, count is set by useState(0), which returns an array with the first element being the variable assigned to 0 and the second element being the value function that can be reset on the first element. Here we assign these two elements to count and setCount respectively through array deconstruction. (If you do not know ES6 deconstruction assignment, please refer to the relevant part of Teacher Ruan Yifeng’s ES6 book first.)

We also use useEffect(), which defines a timer in the function and then returns a function that clears the timer. This function is equivalent to the componentWillUnmount() life subfunction in the class component. The useEffect() function itself is equivalent to the componentDidMount() lifecycle function.

It returns the second element of the array setCount(), which is a higher-order function. We need to pass c => c + 1 as an argument, This higher-order function passes count to c => c + 1 and reassigns the calculated value to count.

State Hooks

useState()

Use useReducer(), which is the basic state management Hook

useState(0)

The 0 passed to useState simply sets a default value for the state, and it is useless when the state changes.

It returns two elements that I think you all know what they are, but the second element here, it can be used in two ways, right

  • setCount( 100 )Pass a certain value
  • setCount( c => c + 1)Pass a function the way we used it above

SetCount (count + 1) = 1 setCount(count + 1) = 1 Why is this happening? This is due to the closure. After the state update, the function component we created is re-executed. Const [count, setCount] = useState(0) is re-executed, and count is reset to 0 each time, and then updated to 1.

Closure episodes:

Which are in large part caused by Hooks that are difficult to learn. In fact, it is because of the Hooks that are not mastering closures. Here’s a brief description.

Tips: Please note that if you have read other articles and have never understood closures, don’t worry, I am confident that 90% of the people who read my articles will understand what closures are. Have the foundation direct skip!!

Closure first, scope

So let’s get out of the let,const way of defining variables, and go back to the beginning. Var in JavaScript, before ES6, didn’t have block-level scope, but it did have something called function scope

var glob = 'I'm the outermost variable defined'

function func1() {
    console.log(glob) // We can refer to upper-level variables here
    var f1 = 'I'm a variable in func1'
    
    function func1_1() {
        var f1_1 = 'I'm a variable in function func1_1'
        console.log(glob) 
        console.log(f1)  // We can get the variables defined in the previous function and the outermost variable
    }
    function func1_1() {
        console.log(glob) // We can get the outermost variable here
        console.log(f1_1) // Do not get the same level of function defined variables}}Copy the code

The above code and comments should give you a sense of scope in JavaScript. A function is a function that can’t get a variable defined in the same level of function, but can get a variable defined in the parent level, grandparent level, grandparent level. We can use this property to encapsulate variables.

Function func1(param) {var f2 = param; function func1(param) {function f1 = param; // Assign param to f2, Function func1_1() {console.log(f1, f2)} return func1_1} console.log(f1, f2)} return func1_1} console.log(f1, f2) Func1 = func1('hello') var res1 = func1('hello') // The result is a function (func1_1) that we returned, penalizing ourselves for guessing wrong, give me a thumbs up, hahaha. Res1 () // res1 stores the returned func1_1, so run it again // prints out the variable 'hello' for my grandchildren onlyCopy the code

Func1 (‘hello’) ends its life cycle, and its definitions of F1 and F2 should never be accessed again, but func1_1 saved them for it, keeping it alive

This encapsulates variables as closures.

Closure episode ends

Let’s go back to the above

We can avoid the closure quirks by passing in the callback function setCount(c => c + 1).

useReducer

function countReducer(state, action) {
    switch(action.type) {
        case 'add': 
            return state + 1;
        case 'minus': 
            return state - 1;
        default:
            return state
    }
}

......
// const [count, setCount] = useState(0)
const [count, dispatchCount] = useReducer(countReducer,0); .// setCount(c => c + 1)
dispatchCount({ type: 'add'})...Copy the code

First, we define a reducer outside CounterFunc, and then change the definition of count and update count. Here, the use of useReducer is similar to the operation in Redux, and we will continue to update the use of Redux.

Note that useReducer(countReducer,0) takes two arguments. The first is the countReducer defined and the second is the default. The second element we receive in return is always dispach, or dispachCount as we wrote here.

summary

The following five points are shared: one is the difference between a function component and a class component, another is useState, another is useEffect (more details later), then introduces closures, and finally explains the use of useReducer. React-hooks. React-hooks. React-hooks.