React Hooks(一) useState

1. What is React Hooks

Before talking about the usage of useState, let's take a look at what React Hooks are.

Hooks are actually stateful functional components. Closures are the core of react hooks.

Closure

A closure is a special object consisting of two parts, the execution context A and the function B created in A. When executing B, if the variable object in A is accessed, then the closure will be generated.

 // 执行上下文,这里暂时写为一个函数,它也可以指一个模块
 const A = () => {
    
    
   const a = "aaa" 
   const B = () => {
    
     
        // 注意这里可以修改a的值
      console.log(a)  
     // 当B执行时,如果访问了A中的变量,那就产生闭包,这里称A(执行上下文)为闭包
   }
 }

When we define a react component and use it in other modules, closures are generated.

// 这里把A.js看成是一个模块
export const A = () => {
    
     
    const a = 'aaa'
 }
// B.js
import {
    
     A } from './A.js'
const B = () => {
    
     
    // 这里把B.js看成是另一个组件,引入A组件,并且访问A组件中的变量,此时形成闭包, B里可以修改a的值
    console.log(a) 
}

According to the characteristics of the closure, the a variable in the A module will persist, so when the B function is executed again, we can also get the value of a at the end of the last B function execution.
We can write a custom useState based on the principle of closure.

// state.js模块 对应上面的A.js
let state = null;

export const useState = (value) => {
    
    
    // 第一次调用的时候没有初始值,因此使用传入的初始值赋值
    state = state || value
    function dispatch(newValue) => {
    
    
        state = newValue
        
    }
    return [state, dispatch]
}

// 在其他模块中引入并使用 对应上面的B.js 相当于是一个hooks组件
import React from 'react'
import {
    
     useState } from './state'

export default function Demo() {
    
     
    const [count, setCount] = useState(0)
    return <button onClick={
    
    () => setCount(count + 1)}>{
    
    count}</button>}

React uses a top-down one-way data flow method to manage its own data and state. Data can only be triggered by the parent component and passed down to the child component. So in react, changes in state and props will cause the component to re-render. If it is a change in the parent component, the child components under the parent component will also be re-rendered.
Rendering method:
class component: re-execute the render method;
functional component: re-execute the entire function;

二 useState()

The main function of useState() is to save the state, and it receives a parameter that is the default value. It returns an array, the first array is the data, and the second is the method to manipulate the data.
Let's look at a simple example:

import React, {
    
     useState } from 'react';

function Bulbs() {
    
    
  const [on, setOn] = useState(false);

  const lightOn = () => setOn(true);
  const lightOff = () => setOn(false);

  //lightOn和lightOff实际上用lightSwitch一个方法就够了
  const lightSwitch = () => setOn(on => !on);

  return (
    <>
      <div className={
    
    on ? 'bulb-on' : 'bulb-off'} />
      <button onClick={
    
    lightOn}>开灯</button>
      <button onClick={
    
    lightOff}>关灯</button>
    </>
  );
}

1. Usage

(1) useState receives a value as the initial value of the current state. Only executed when the component renders for the first time . Functions can also be passed in as parameters.
Here's an example of passing in a function:

const a = 10
const b = 20
const [count, setCount] = useState(() => {
    
    
    return a + b
})

(2) Update state using callback

const [toggled, setToggled] = useState(false);
setToggled(toggled => !toggled);

const [count, setCount] = useState(0);
setCount(count => count + 1);

// 数组的修改要注意
const [items, setItems] = useState([]);
setItems(items => [...items, 'New Item']);

2. Issues to be aware of

(1) useState() is only called at the top level, and only called inside function components or custom hooks. Cannot be called in loops, conditionals, nested functions.
(2) Obsolete state
A closure is a function that captures variables from an outer scope. Since state variables change between renders, the closure should capture the variable with the latest state value, otherwise, you may run into stale state issues.

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

  const handleClickAsync = () => {
    
    
    setTimeout(function delay() {
    
    
      setCount(count + 1);
    }, 3000);
  }

  return (
    <div>
      {
    
    count}
      <button onClick={
    
    handleClickAsync}>Increase async</button>
    </div>
  );
}

The button is clicked multiple times quickly, the count variable does not correctly record the actual number of clicks, and some clicks are eaten.
To solve this problem, use the function method to update the count state, just setCount(count + 1);change tosetCount(count => count + 1);

Guess you like

Origin blog.csdn.net/LittleMoon_lyy/article/details/124518285
Recommended