React-useState讲解
useState
让页面“动”起来
例如实现一个 click 计数功能,普通变量无法实现。即:修改普通变量无法触发组件的更新 rerender
通过 useState 即可实现。
state 是什么
State, A component’s memory —— 这个比喻非常好!
- props 父组件传递过来的信息
- state 组件自己内部的状态,不对外
每次 state 变化,都会触发组件更新,从新渲染页面。
代码演示,参考 react-ts-demo 中 pages/StateDemo1.tsx
import React, { FC, useState } from 'react'const Demo: FC = () => {// let count = 0 // 普通的 js 变量,无法触发组件的更新const [count, setCount] = useState(0) // useState 可以触发组件的更新,// const [name, setName] = useState('双越')function add() {// count++// setCount(count + 1)setCount(count => count + 1) // 使用函数,state 更新不会被合并setCount(count => count + 1)setCount(count => count + 1)setCount(count => count + 1)setCount(count => count + 1)// setCount(count => count + 1)console.log('cur count ', count) // 异步更新,无法直接拿到最新的 state 值}return (<div><button onClick={add}>add {count}</button></div>)
}export default Demo
state 的特点
异步更新
代码演示
PS:setState 传入函数,可同步更新
可能会被合并
代码演示
不可变数据
state 可以是任意 JS 类型,不仅仅是值类型。
不可直接修改 state ,而要 setState 新值。
代码演示
PS:函数组件,每个更新函数从新执行,state 被重置,而不是被修改。state 可以理解为 readOnly
immer
Immer 简化了不可变数据结构的处理。特别是对于 JS 语法没那么熟悉的人。
代码演示,参考 react-ts-demo 中 pages/ImmerDemo1.tsx
import React, { FC, useState } from 'react'
import produce from 'immer'const Demo: FC = () => {// const [userInfo, setUserInfo] = useState({ name: '柚子', age: 20 })// function changeAge() {// // // **不可变数据** - 不去修改 state 的值,而是要传入一个新的值 —— 重要!// // setUserInfo({// // ...userInfo,// // age: 21,// // })// setUserInfo(// produce(draft => {// draft.age = 21// })// )// }const [list, setList] = useState(['x', 'y'])function addItem() {// // **不可变数据** - 不去修改 state 的值,而是要传入一个新的值 —— 重要!// setList(list.concat('z'))// // setList([...list, 'z'])setList(produce(draft => {draft.push('z')}))}return (<div><h2>state 不可变数据</h2>{/* <div>{JSON.stringify(userInfo)}</div><button onClick={changeAge}>change age</button> */}<div>{JSON.stringify(list)}</div><button onClick={addItem}>add item</button></div>)
}export default Demo
实战:List 页面使用 state
- 使用 state
- 使用 immer
- push
- 修改 isPublish
代码参考 pages/List2.tsx
import React, { FC, useState, useEffect } from 'react'
import produce from 'immer'
import QuestionCard from './components/QuestionCard'// 组件是一个函数(执行返回 JSX 片段),组件初次渲染执行这个函数
// 任何 state 更新,都会触发组件的更新(重新执行函数)
const List2: FC = () => {useEffect(() => {console.log('加载 ajax 网络请求')return () => {console.log('销毁')}}, []) // 无依赖,组件初次渲染时执行// const [count, setCount] = useState(0)const [questionList, setQuestionList] = useState([{ id: 'q1', title: '问卷1', isPublished: false },{ id: 'q2', title: '问卷2', isPublished: true },{ id: 'q3', title: '问卷3', isPublished: false },{ id: 'q4', title: '问卷4', isPublished: true },])// useEffect(() => {// console.log('question list changed')// }, [questionList])// useEffect(() => {// console.log('count changed')// }, [count, questionList])function add() {// setCount(count + 1)const r = Math.random().toString().slice(-3)// setQuestionList(// // 新增 concat// questionList.concat({// id: 'q' + r,// title: '问卷' + r,// isPublished: false,// })// )// immer 的方式setQuestionList(produce(draft => {draft.push({id: 'q' + r,title: '问卷' + r,isPublished: false,})}))}function deleteQuestion(id: string) {// // 不可变数据// setQuestionList(// // 删除 filter// questionList.filter(q => {// if (q.id === id) return false// else return true// })// )// immer 的方式setQuestionList(produce(draft => {const index = draft.findIndex(q => q.id === id)draft.splice(index, 1)}))}function publishQuestion(id: string) {// setQuestionList(// // 修改 map// questionList.map(q => {// if (q.id !== id) return q// return {// ...q,// isPublished: true,// }// })// )// immer 的方式setQuestionList(produce(draft => {const q = draft.find(item => item.id === id)if (q) q.isPublished = true}))}return (<div><h1>问卷列表页2</h1><div>{questionList.map(question => {const { id, title, isPublished } = questionreturn (<QuestionCardkey={id}id={id}title={title}isPublished={isPublished}deleteQuestion={deleteQuestion}publishQuestion={publishQuestion}/>)})}</div><div><button onClick={add}>新增问卷</button></div></div>)
}export default List2
代码参考 /components/QuestionCard
import React, { FC, useEffect } from 'react'
import classnames from 'classnames'
// import './QuestionCard.css'
import styles from './QuestionCard.module.scss'// ts 自定义类型
type PropsType = {id: stringtitle: stringisPublished: booleandeleteQuestion?: (id: string) => voidpublishQuestion?: (id: string) => void
}// FC - functional component
const QuestionCard: FC<PropsType> = props => {const { id, title, isPublished, deleteQuestion, publishQuestion } = propsfunction publish(id: string) {publishQuestion && publishQuestion(id)}function del(id: string) {deleteQuestion && deleteQuestion(id)}// useEffect(() => {// console.log('question card mounted')// return () => {// console.log('question card unmounted', id) // 销毁// }// // 生命周期:创建,更新(state 变化),销毁// }, [])// let itemClassName = 'list-item'// if (isPublished) itemClassName += ' published'// // 逻辑稍微复杂// const itemClassName = classnames('list-item', { published: isPublished })// const itemClassName = classnames({// 'list-item': true,// published: isPublished,// })const listItemClass = styles['list-item']const publishedClass = styles.publishedconst itemClassName = classnames({[listItemClass]: true,[publishedClass]: isPublished,})return (<div key={id} className={itemClassName}><strong>{title}</strong> {/* 条件判断 */}{isPublished ? <span className={styles['published-span']}>已发布</span> : <span>未发布</span>} <buttononClick={() => {publish(id)}}>发布问卷</button> <buttononClick={() => {del(id)}}>删除问卷</button></div>)
}export default QuestionCard
最重要的就是:不可变数据 —— 这是 React state 的核心
相关文章:
React-useState讲解
useState 让页面“动”起来 例如实现一个 click 计数功能,普通变量无法实现。即:修改普通变量无法触发组件的更新 rerender 通过 useState 即可实现。 state 是什么 State, A component’s memory —— 这个比喻非常好! props 父组件传…...
混币器是什么,波卡跨链交易平台
混币器是什么 混币器是一种加密货币工具,主要功能是将用户的加密货币与其他众多用户的加密货币混合在一起,打乱资金的流向和交易痕迹,使得加密货币的来源和去向难以追踪,从而增加交易的匿名性和隐私性。以下是对其工作流程和相关举例的介绍: 工作流程 用户首先将自己的加…...
【PHP】双方接口通信校验服务
请求方 使用 ApiAuthService::buildUrl($domain, [terminal > 1, ts > time()]); //http://域名/adminapi/login/platformLogin?signF7FE8A150DEC18BE8A71C5059742C81A&terminal1&ts1736904841接收方 $getParams $this->request->get();$validate ApiA…...

Web第一次作业
目录 题目 html代码 index login register css代码 base index login register 效果展示 index login register 题目 实现一个登录页面、实现一个注册页面;实现一个主页 - 登录页面:login.html - 注册页面:register.html - 主页…...
CentOS 6.8 安装 Nginx
个人博客地址:CentOS 6.8 安装 Nginx | 一张假钞的真实世界 提前安装: # sudo yum install yum-utils 一般情况下这个工具系统已经安装。 创建文件/etc/yum.repos.d/nginx.repo,输入内容如下: [nginx-stable] namenginx stab…...

网络网络层ICMP协议
网络网络层ICMP协议 1. ICMP 协议介绍 ICMP(Internet Control Message Protocol)是 TCP/IP 协议簇中的网络层控制报文协议。用于在 IP 主机、路由器之间传递控制消息,提供可能有关通信问题的反馈信息。 以及用于网络诊断或调试(…...
当父级元素设置了flex 布局 ,两个子元素都设置了flex :1, 但是当子元素放不下的时候会溢出父元素怎么解决 (css 样式问题)
一、问题 遇到个样式问题,当父级元素设置了flex 布局 ,两个子元素都设置了flex :1, 但是当子元素放不下的时候会溢出父元素怎么解决 (拖拽浏览器 使页面变小) 二、解决方法 .father{min-height: 600px;width: 100%;display: flex…...
Vue.js组件开发-如何实现路由懒加载
在Vue.js应用中,路由懒加载是一种优化性能的技术,它允许在需要时才加载特定的路由组件,而不是在应用启动时加载所有组件。这样可以显著减少初始加载时间,提高用户体验。在Vue Router中,实现路由懒加载非常简单…...
灵活妙想学数学
灵活妙想学数学 题1:海星有几只? 一共有12只海洋生物,分别是5只脚的海星,8只脚的章鱼和10只脚的鱿鱼,这些海洋动物的脚一共有87只,每种生物至少有1只,问海星有几只? 解:…...

使用 Multer 上传图片到阿里云 OSS的两种方式
文件上传到哪里更好? 上传到服务器本地 上传到服务器本地,这种方法在现今商业项目中,几乎已经见不到了。因为服务器带宽,磁盘 IO 都是非常有限的。将文件上传和读取放在自己服务器上,并不是明智的选择。 上传到云储存…...

破解合同管理之痛,开启智能化管理新模式
合同管理是采购管理中的一项重要环节,涉及合同洽谈、草拟、签订、生效、履行、失效全过程。随着企业业务规模的发展壮大,企业与各类供应商之间的合作往来更加频繁,需要签署和管理的合同文件也不断增多,如何提升合同管理效率成为企…...

Linux-day06
第14章 进程管理(重点) 进程基本介绍 程序运行起来就是一个进程 1.程序和进程的关系 2.在Linux中有两种方式执行,一种叫前台,一种后台 ps指令详解 显示系统执行的进程 USER:进程执行用户 PID:进程号 …...

源码编译安装httpd 2.4,提供系统服务管理脚本并测试
总结需要安装的包 sudo yum groupinstall "Development Tools" -y #httpd的依赖包yum install tar -y #tar压缩包sudo yum install apr-devel apr-util-devel #APR库 提供跨平台接口的库sudo yum install pcre pcre-devel # PCRE库和 pcre-config工具--提供PCRE库…...

Linux固定ip
进入etc/sysconfig/network-scripts目录 cd /etc/sysconfig/network-scripts 编辑ifcfg-ens33文件 vi ifcfg-ens33 将BOOTPROTO的值改为“static”,在文档最后添加需要的固定IP BOOTPROTO"static" IPADDR192.168.132.136点击按键“esc”,…...
Java 输入输出流(上)
目录 1.Java 输入输出流 2.Java File类 3.Java File类目录 1.创建目录 2.列出目录中的文件 4.Java File类文件 1.文件的创建与删除 2.运行可执行文件 5.Java 文件字节输入流(1) 6.Java 文件字节输入流(2) 1.使用输入流读取字节 2.关闭流 7.Java 文件字节输出流(1…...
mysql、oracle、sqlserver的区别
一、保存数据的持久性: MySQL:是在数据库更新或者重启,则会丢失数据。 Oracle:把提交的sql操作线写入了在线联机日志文件中,保持到了磁盘上,可以随时恢复。 SqlServer:2…...

Java+Maven+GDAL
下载已经编译好的压缩包,下载地址 解压 jar 包 release-1930-x64-dev.zip\release-1930-x64\bin\gdal\java 目录下 打成Maven依赖 mvn install:install-file -Dfilegdal-3.10.1.jar -DgroupIdorg.gdal -DartifactIdgdal -Dversion3.10.1 -Dpackagingjar -Dgener…...

初识算法和数据结构P1:保姆级图文详解
文章目录 前言1、算法例子1.1、查字典(二分查找算法)1.2、整理扑克(插入排序算法)1.3、货币找零(贪心算法) 2、算法与数据结构2.1、算法定义2.2、数据结构定义2.3、数据结构与算法的关系2.4、独立于编程语言…...

【Go】Go Gorm 详解
1. 概念 Gorm 官网:https://gorm.io/zh_CN/docs/ Gorm:The fantastic ORM library for Golang aims to be developer friendly,这是官网的介绍,简单来说 Gorm 就是一款高性能的 Golang ORM 库,便于开发人员提高效率 那…...
【IDEA版本升级JDK21报错方法引用无效 找不到符号】
java: 方法引用无效 找不到符号 符号: 方法 getFirst() 位置: 接口 java.util.List 升级JDK21版本遇到问题,报错找不到符号 但是点进去又能发现这个函数,证明能够找到这个方法,但是就是报错 java: 方法引用无效 找不到符号 符号: …...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...

C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...
WebRTC从入门到实践 - 零基础教程
WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC? WebRTC(Web Real-Time Communication)是一个支持网页浏览器进行实时语音…...
Docker拉取MySQL后数据库连接失败的解决方案
在使用Docker部署MySQL时,拉取并启动容器后,有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致,包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因,并提供解决方案。 一、确认MySQL容器的运行状态 …...

如何在Windows本机安装Python并确保与Python.NET兼容
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...
「Java基本语法」变量的使用
变量定义 变量是程序中存储数据的容器,用于保存可变的数据值。在Java中,变量必须先声明后使用,声明时需指定变量的数据类型和变量名。 语法 数据类型 变量名 [ 初始值]; 示例:声明与初始化 public class VariableDemo {publi…...