首页 > 其他分享 >React - 12 Hooks组件之useState

React - 12 Hooks组件之useState

时间:2023-06-29 20:32:44浏览次数:60  
标签:supNum 12 const Hooks React state useState setNum Demo

1.hooks组件本质是函数组件

React - 12 Hooks组件之useState_react

2.useState

①基础用法

import React, { useState } from "react";
import { Button } from 'antd';
/*
 useState:React Hook函数之一,目的是在函数组件中使用状态,并且后期基于状态的修改,可以让组件更新
   let [num,setNum] = useState(initialValue);
     + 执行useState,传递的initialValue是初始的状态值
     + 执行这个方法,返回结果是一个数组:[状态值,修改状态的方法]
       + num变量存储的是:获取的状态值
       + setNum变量存储的是:修改状态的方法
     + 执行 setNum(value) 
       + 修改状态值为value
       + 通知视图更新

  函数组件「或者Hooks组件」不是类组件,所以没有实例的概念「调用组件不再是创建类的实例,而是把函数执行,产生一个私有上下文而已」,再所以,在函数组件中不涉及this的处理!!
 */
const Demo = function Demo() {
    let [num, setNum] = useState(0);

    const handle = () => {
        setNum(num + 10);
    };
    return <div className="demo">
        <span className="num">{num}</span>
        <Button type="primary" size="small" onClick={handle}>新增</Button>
    </div>;
};

②useState底层机制

React - 12 Hooks组件之useState_react_02

函数组件的每一次渲染(或者是更新),都是把函数(重新)执行,产生一个全新的“私有上下文”!
   + 内部的代码也需要重新执行
   + 涉及的函数需要重新的构建{这些函数的作用域(函数执行的上级上下文),是每一次执行DEMO产生的闭包}
   + 每一次执行DEMO函数,也会把useState重新执行,但是:
     + 执行useState,只有第一次,设置的初始值会生效,其余以后再执行,获取的状态都是最新的状态值「而不是初始值」
     + 返回的修改状态的方法,每一次都是返回一个新的

var _state;
function useState(initialValue) {
    if (typeof _state === "undefined") {
        if(typeof initialValue==="function"){
            _state = initialValue();
        }else{
            _state = initialValue
        }
    };
    var setState = function setState(value) {
        if(Object.is(_state,value)) return;
        if(typeof value==="function"){
            _state = value(_state);
        }else{
            _state = value;
        }
        // 通知视图更新
    };
    return [_state, setState];
}
let [num1, setNum] = useState(0); //num1=0  setNum=setState 0x001
setNum(100); //=>_state=100 通知视图更新
// ---
let [num2, setNum] = useState(0); //num2=100  setNum=setState 0x002

一个有关底层机制的例子

const Demo = function Demo() {
    let [num, setNum] = useState(0);

    const handle = () => {
        setNum(100);
        setTimeout(() => {
            console.log(num); // 0
        }, 2000);
    };
    return <div className="demo">
        <span className="num">{num}</span>
        <Button type="primary"
            size="small"
            onClick={handle}>
            新增
        </Button>
    </div>;
};

export default Demo;

原理

React - 12 Hooks组件之useState_react_03

useState细节知识和同步异步

③ 更新多个状态

/* 
执行一次useState:把需要的状态信息都放在对象中统一管理
    + 执行setState方法的时候,传递的是啥值,就把状态“整体”改为啥值 
      setState({
        supNum: state.supNum + 1
      }) 
      => 把状态值修改为 {supNum:11} ,oppNum成员就丢失了
      => 并不会像类组件中的this.setState一样,不支持部分状态的更新
    + 应该改为以下的处理方案(官方不推荐)
      setState({
        ...state, //在修改值之前,先把原有的所有状态,都展开赋值给新对象,再去修改要改动的那一项值即可
        supNum: state.supNum + 1
      });
*/
const Vote = function Vote(props) {
    let [state, setState] = useState({
        supNum: 10,
        oppNum: 5
    });

    const handle = (type) => {
        if (type === 'sup') {
            setState({
                ...state,
                supNum: state.supNum + 1
            });
            return;
        }
        setState({
            ...state,
            oppNum: state.oppNum + 1
        });
    };

    return <div className="vote-box">
        <div className="header">
            <h2 className="title">{props.title}</h2>
            <span className="num">{state.supNum + state.oppNum}</span>
        </div>
        <div className="main">
            <p>支持人数:{state.supNum}人</p>
            <p>反对人数:{state.oppNum}人</p>
        </div>
        <div className="footer">
            <Button type="primary" onClick={handle.bind(null, 'sup')}>支持</Button>
            <Button type="primary" danger onClick={handle.bind(null, 'opp')}>反对</Button>
        </div>
    </div>;
};
/* 官方建议是:需要多个状态,就把useState执行多次即可 */
const Vote = function Vote(props) {
    let [supNum, setSupNum] = useState(10),
        [oppNum, setOppNum] = useState(5);

    const handle = (type) => {
        if (type === 'sup') {
            setSupNum(supNum + 1);
            return;
        }
        setOppNum(oppNum + 1);
    };

    return <div className="vote-box">
        <div className="header">
            <h2 className="title">{props.title}</h2>
            <span className="num">{supNum + oppNum}</span>
        </div>
        <div className="main">
            <p>支持人数:{supNum}人</p>
            <p>反对人数:{oppNum}人</p>
        </div>
        <div className="footer">
            <Button type="primary" onClick={handle.bind(null, 'sup')}>支持</Button>
            <Button type="primary" danger onClick={handle.bind(null, 'opp')}>反对</Button>
        </div>
    </div>;
};

④更新队列机制

import React, { useState } from "react";
import { Button } from 'antd';
import './Demo.less';
import { flushSync } from 'react-dom';

const Demo = function Demo() {
    console.log('RENDER渲染');
    let [x, setX] = useState(10),
        [y, setY] = useState(20),
        [z, setZ] = useState(30);
    // flushSync可以将异步立马执行,变同步
    // const handle = () => {
    //     flushSync(() => {
    //         setX(x + 1);
    //         setY(y + 1);
    //     });
    //     setZ(z + 1);
    // };
    const handle = () => {
        setX(x + 1);
        console.log(x) // 10 不是 11,与setX是同步异步没关系,变量作用域链往上找
        setY(y + 1);
        setZ(z + 1);
    };
    return <div className="demo">
        <span className="num">x:{x}</span>
        <span className="num">y:{y}</span>
        <span className="num">z:{z}</span>
        <Button type="primary"
            size="small"
            onClick={handle}>
            新增
        </Button>
    </div>;
};

export default Demo;

React - 12 Hooks组件之useState_react_04

React - 12 Hooks组件之useState_react_05

例子:渲染几次

渲染1次,x: 11

React - 12 Hooks组件之useState_react_06

修改 -->

渲染一次,点击新增后不会更新视图(不会打印渲染),因为useState做了优化机制,前后修改的值一样,不会触发更新

React - 12 Hooks组件之useState_react_07

修改 --> 不是更新10次,实际更新2次(点击按钮后)

React - 12 Hooks组件之useState_react_08

修改 -->

import React, { useState } from "react";
import { Button } from 'antd';
import './Demo.less';
import { flushSync } from 'react-dom';

/*
  useState自带了性能优化的机制:
    + 每一次修改状态值的时候,会拿最新要修改的值和之前的状态值做比较「基于Object.is作比较」
    + 如果发现两次的值是一样的,则不会修改状态,也不会让视图更新「可以理解为:类似于PureComponent,在shouldComponentUpdate中做了浅比较和优化」
 */

// 需求:让函数只更新一次,但是最后的结果是20
const Demo = function Demo() {
    console.log('RENDER渲染');
    let [x, setX] = useState(10);

    const handle = () => {
        for (let i = 0; i < 10; i++) {
            setX(prev => {
                // prev:存储上一次的状态值
                console.log(prev);
                return prev + 1; //返回的信息是我们要修改的状态值
            });
        }
    };
    return <div className="demo">
        <span className="num">x:{x}</span>
        <Button type="primary"
            size="small"
            onClick={handle}>
            新增
        </Button>
    </div>;
};

export default Demo;

执行原理

React - 12 Hooks组件之useState_react_09

⑤设置初始值时使用惰性

useState中传入的函数只在第一次熏染组价时触发,这是用来计算初始值的

import React, { useState } from "react";
import { Button } from 'antd';
import './Demo.less';

const Demo = function Demo(props) {
    // 我们需要把基于属性传递进来的x/y,经过其他处理的结果作为初始值
    // 此时我们需要对初始值的操作,进行惰性化处理:只有第一次渲染组件处理这些逻辑,以后组件更新,这样的逻辑就不要再运行了!!
    let [num, setNum] = useState(() => {
        let { x, y } = props,
            total = 0;
        for (let i = x; i <= y; i++) {
            total += +String(Math.random()).substring(2);
        }
        return total;
    });

    const handle = () => {
        setNum(1000);
    };
    return <div className="demo">
        <span className="num">{num}</span>
        <Button type="primary"
            size="small"
            onClick={handle}>
            新增
        </Button>
    </div>;
};

export default Demo;



标签:supNum,12,const,Hooks,React,state,useState,setNum,Demo
From: https://blog.51cto.com/u_12207234/6584885

相关文章

  • 【雕爷学编程】Arduino动手做(138)---64位WS2812点阵屏模块
    37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里准备逐一动手尝试系列实验,不管成功(程序走通)与否,都会记录下来—小小的进步或是搞......
  • 12. 强制类型转换
    目录1.Defination2.整数提升3.常用的算术转换1.Defination  即把数据类型转换成另一种数据类型,例如这么一种情况,你想把long类型的数据,保存成int类型数据,那么你就需要将其进行强制类型转换。可以使用强制类型转换运算符来把值显示的转换成另一种数据类型。(type_name)expr......
  • react保姆级搭建新项目
    此文主要以ts+vite+router6+antd快速搭建一个react项目,适用于初学者一、项目搭建采用pnpm,个人感觉比npm和yarn好用npmipnpm-g采用vite方式,根据选择react-tspnpmcreatevite1.1修改初始结构,删除多余文件1.2修改vite.config配置文件配置别名vite.config:import{defineC......
  • thinkphp6:使用view视图/模板(thinkphp v6.0.12LTS)
    一,在使用之前,需要用composer安装需要的view模块:参见:https://blog.imgtouch.com/index.php/2023/06/29/thinkphp6-bao-cuo-driver-think-not-supported/二,php代码:<?phpdeclare(strict_types=1);namespaceapp\controller;useapp\BaseController;usethink\fa......
  • 获取邮箱(QQ、126、163)的客户端授权码
    获取QQ邮箱的客户端授权码1、首先登录QQ邮箱(https://mail.qq.com),然后,点击“设置”按钮。2、点击“账户”按钮,进入“账户”页面。3、在账户页面将页面往下拉,找到pop3设置,选择“开启”。4、据要求进行验证(此处以手机密保验证为例),验证完毕后,点击“我已发送”按钮。5、接下来......
  • 力扣---1253. 重构 2 行二进制矩阵
    给你一个 2 行 n 列的二进制数组:矩阵是一个二进制矩阵,这意味着矩阵中的每个元素不是 0 就是 1。第 0 行的元素之和为 upper。第 1 行的元素之和为 lower。第 i 列(从 0 开始编号)的元素之和为 colsum[i],colsum 是一个长度为 n 的整数数组。你需要利用 ......
  • uva 12470(矩阵快速幂)
    题意:公式f(n)=f(n-1)+f(n-2)+f(n-3),给出n,f(1)=0,f(2)=1,f(3)=2,要求得出f(n)。题解:普通的矩阵快速幂模板题。#include<stdio.h>#include<string.h>constintMOD=1000000009;structMat{longlongg[3][3];}ori,res;longlongn;Matmultiply(......
  • 牛客练习赛112 B qsgg and Subarray
    这里介绍两种解法,贪心和二分核心:只要某一个区间和为0,则所有包含该区间的和都为0贪心根据题意是求出所有⊕和为0的子区间的个数,我们按a[i]来分类,每次求出以a[i]为末尾,区间和为0的区间个数,对于a[i]来说,要想u~i的区间和为0,则需要包含所有a[i]中位为1都有0与之对应,如果u~i的区间和......
  • AGC012E Camel and Oases
    题意有一个数轴上有\(n\)个点。一开始有一个参数\(v\),你可以进行任意次移动,直到\(v=0\):移动到一个距离当前点不超过\(v\)的点,\(v\)不变。移动到任何一个点,使得\(v\gets\lfloor\dfrac{v}{2}\rfloor\)。现在对于每个起点,问从这个点出发可不可以遍历所有位置。\(1......
  • uva 123(排序、检索)
    题目:Searchingandsortingarepartofthetheoryandpracticeofcomputerscience.Forexample,binarysearchprovidesagoodexampleofaneasy-to-understandalgorithmwithsub-linearcomplexity.Quicksortisanefficient[averagecase]comparisonbased......