0302useState-hooks-react-仿低代码平台项目

文章目录

    • 1 useState
      • 1.1 说明
        • 返回
      • 1.2 示例
      • 1.3 数据类型
    • 2 state
      • 2.1 概述
      • 2.2 state特点
    • 3 state重构问卷
    • 4 immer
    • 结语

1 useState

useState 是一个 React Hook,它允许你向组件添加一个 状态变量。

1.1 说明

  • 语法
const [state, setState] = useState(initialState)
  • 参数 initialState: 你希望 state 初始化的值。它可以是任何类型的值,但对于函数有特殊的行为。在初始渲染后,此参数将被忽略。
  • 如果传递函数作为 initialState,则它将被视为 初始化函数。它应该是纯函数,不应该接受任何参数,并且应该返回一个任何类型的值。当初始化组件时,React 将调用你的初始化函数,并将其返回值存储为初始状态。
返回

useState 返回一个由两个值组成的数组:

  1. 当前的 state。在首次渲染时,它将与你传递的 initialState 相匹配。
  2. set 函数,它可以让你将 state 更新为不同的值并触发重新渲染。

1.2 示例

如下是一个简单的点击按钮累加的示例:

import { useState } from "react";
function Acc() {// 普通js变量无法触发组件更新// let count = 0;//useState可以触发组件更新const [count, setCount] = useState(0);// 点击累加function add() {setCount(count + 1);}return (<><button onClick={add}> click to accumulate:{count} </button></>);
}export default Acc;

普通js变量无法触发组件更新,如下图所示:在这里插入图片描述

使用useState实现页面组件更新,如下图所示:在这里插入图片描述

1.3 数据类型

useState(0)
useState('a')
useState({"a": 1, "b": 2})
useState([1,2,3])
  • xxx类型没有限制,可以是任意类型

2 state

2.1 概述

组件可以拥有状态(state),它是组件数据的私有部分,可以用来管理动态数据。

状态仅适用于类组件,或者使用 React 的 Hook 时可以在函数组件中使用。

React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。

React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。

以下实例创建一个名称扩展为 React.Component 的 ES6 类,在 render() 方法中使用 this.state 来修改当前的时间。

添加一个类构造函数来初始化状态 this.state,类组件应始终使用 props 调用基础构造函数。


2.2 state特点

  • State异步更新,示例代码如下

    import { FC, useState } from "react";
    const StateDemo01: FC = () => {//useState可以触发组件更新const [count, setCount] = useState(0);const [name, setName] = useState("张三");// 点击累加function add() {setCount(count + 1);console.log(count);//如果一个变量不用于jsx中显示,不要用useState管理它,用useRef.setName("李四");}return (<><button onClick={add}> click to accumulate:{count} </button></>);
    };export default StateDemo01;
    

打印结果如下所示:在这里插入图片描述

  • state可能会被合并,

      // 点击累加function add() {setCount(count + 1);setCount(count + 1);setCount(count + 1);setCount(count + 1);setCount(count + 1);console.log(count);//如果一个变量不用于jsx中显示,不要用useState管理它,用useRef.// setName("李四");}
    

    页面结果如上所示,如果想要不被合并,参数传入函数,代码如下:

        setCount((count) => count + 1);
    
  • 不可变数据,如需修改数据,需要传入新值

    import { FC, useState } from "react";
    const StateDemo02: FC = () => {//useState可以触发组件更新const [userInfo, setUserInfo] = useState({ name: "张三", age: 20 });// 点击累加function edit() {// 不可变数据,不去修改state的值,而是传入一个新的值或者返回一个新值的函数或者表达式// setUserInfo({ name: "张三", age: 21 }); // 全量语法setUserInfo({ ...userInfo, age: 21 }); // 结构语法}return (<><h3>state:不可变数据</h3><div> {JSON.stringify(userInfo)} </div><button onClick={edit}> 修改年龄 </button></>);
    };export default StateDemo02;

    修改数组

    setXxx([...arr, 5])
    setXxx(arr.concat(5))
    

3 state重构问卷

  • state替换文件列表

    import { FC, useState } from "react";import QuestionCard from "./QuestionCard";
    const List2: FC = () => {//列表页//问卷列表数据const questions = [{ id: "q1", title: "问卷1", isPublished: false },{ id: "q2", title: "问卷2", isPublished: false },{ id: "q3", title: "问卷3", isPublished: true },{ id: "q4", title: "问卷4", isPublished: false },{ id: "q5", title: "问卷5", isPublished: true },];const [questionList, setQuestionList] = useState(questions);const r = Math.random().toString().slice(-3);return (<div><h1>问卷列表页</h1><div>{questionList.map((q) => {const { id, title, isPublished } = q;return (<QuestionCardkey={id}id={id}title={title}isPublished={isPublished}/>);})}</div></div>);
    };export default List2;
  • 新增问卷

    import { FC, useState } from "react";import QuestionCard from "./QuestionCard";
    const List2: FC = () => {//列表页//问卷列表数据const questions = [{ id: "q1", title: "问卷1", isPublished: false },{ id: "q2", title: "问卷2", isPublished: false },{ id: "q3", title: "问卷3", isPublished: true },{ id: "q4", title: "问卷4", isPublished: false },{ id: "q5", title: "问卷5", isPublished: true },];const [questionList, setQuestionList] = useState(questions);const r = Math.random().toString().slice(-3);// 新增问卷function add() {setQuestionList([...questionList,{id: "q" + r,title: "问卷" + r,isPublished: false,},]);}return (<div><h1>问卷列表页</h1><div>{questionList.map((q) => {const { id, title, isPublished } = q;return (<QuestionCardkey={id}id={id}title={title}isPublished={isPublished}/>);})}</div><div><button onClick={add}>新增问卷</button></div></div>);
    };export default List2;
    

    效果如下所示:在这里插入图片描述

    • 删除问卷

    List2.tsx代码如下:

    import { FC, useState } from "react";import QuestionCard from "./components/QuestionCard";
    const List2: FC = () => {//列表页//问卷列表数据const questions = [{ id: "q1", title: "问卷1", isPublished: false },{ id: "q2", title: "问卷2", isPublished: false },{ id: "q3", title: "问卷3", isPublished: true },{ id: "q4", title: "问卷4", isPublished: false },{ id: "q5", title: "问卷5", isPublished: true },];const [questionList, setQuestionList] = useState(questions);const r = Math.random().toString().slice(-3);// 新增问卷function add() {setQuestionList([...questionList,{id: "q" + r,title: "问卷" + r,isPublished: false,},]);}// 删除问卷function deleteQuestion(id: string) {setQuestionList(questionList.filter((q) => {return q.id !== id;}));}return (<div><h1>问卷列表页</h1><div>{questionList.map((q) => {const { id, title, isPublished } = q;return (<QuestionCardkey={id}id={id}title={title}isPublished={isPublished}deleteQuestion={deleteQuestion}/>);})}</div><div><button onClick={add}>新增问卷</button></div></div>);
    };export default List2;
    

    QuestionCard.tsx代码如下:

    import React, { FC } from "react";import "./QuestionCard.css";type PropsType = {id: string;title: string;isPublished: boolean;deleteQuestion: (id: string) => void;
    };const QuestionCard: FC<PropsType> = (props) => {const { id, title, isPublished, deleteQuestion } = props;//编辑问卷function edit(id: string) {console.log("id:", id);}// 删除问卷function del(id: string) {deleteQuestion(id);}return (<div key={id} className="list-item"><strong>{title}</strong>&nbsp;{/* 条件判断 */}{isPublished ? (<span style={{ color: "green" }}>已发布</span>) : (<span>未发布 </span>)}&nbsp;<button onClick={() => edit(id)}>编辑问卷</button>&nbsp;<button onClick={() => del(id)}>删除问卷</button></div>);
    };export default QuestionCard;
    

    页面效果如下图所示:在这里插入图片描述

  • 发布问卷

List2.tsx代码如下:

import { FC, useState } from "react";import QuestionCard from "./components/QuestionCard";
const List2: FC = () => {//列表页//问卷列表数据const questions = [{ id: "q1", title: "问卷1", isPublished: false },{ id: "q2", title: "问卷2", isPublished: false },{ id: "q3", title: "问卷3", isPublished: true },{ id: "q4", title: "问卷4", isPublished: false },{ id: "q5", title: "问卷5", isPublished: true },];const [questionList, setQuestionList] = useState(questions);const r = Math.random().toString().slice(-3);// 新增问卷function add() {setQuestionList([...questionList,{id: "q" + r,title: "问卷" + r,isPublished: false,},]);}// 删除问卷function deleteQuestion(id: string) {setQuestionList(questionList.filter((q) => {return q.id !== id;}));}// 删除问卷function publishQuestion(id: string) {setQuestionList(questionList.map((q) => {if (q.id !== id) {return q;}return {...q,isPublished: true,};}));}return (<div><h1>问卷列表页</h1><div>{questionList.map((q) => {const { id, title, isPublished } = q;return (<QuestionCardkey={id}id={id}title={title}isPublished={isPublished}deleteQuestion={deleteQuestion}publishQuestion={publishQuestion}/>);})}</div><div><button onClick={add}>新增问卷</button></div></div>);
};export default List2;

QuestionCard.tsx代码如下:

import React, { FC } from "react";import "./QuestionCard.css";type PropsType = {id: string;title: string;isPublished: boolean;deleteQuestion?: (id: string) => void;publishQuestion?: (id: string) => void;
};const QuestionCard: FC<PropsType> = (props) => {const { id, title, isPublished, deleteQuestion, publishQuestion } = props;//编辑问卷function edit(id: string) {console.log("id:", id);}// 删除问卷function del(id: string) {deleteQuestion && deleteQuestion(id);}// 发布问卷function publish(id: string) {publishQuestion && publishQuestion(id);}return (<div key={id} className="list-item"><strong>{title}</strong>&nbsp;{/* 条件判断 */}{isPublished ? (<span style={{ color: "green" }}>已发布</span>) : (<span>未发布 </span>)}&nbsp;<button onClick={() => edit(id)}>编辑问卷</button>&nbsp;<button onClick={() => del(id)}>删除问卷</button>&nbsp;<button onClick={() => publish(id)}>发布问卷</button></div>);
};export default QuestionCard;

4 immer

如果你的 state 有多层的嵌套,你或许应该考虑 将其扁平化。但是,如果你不想改变 state 的数据结构,你可能更喜欢用一种更便捷的方式来实现嵌套展开的效果。Immer 是一个非常流行的库,它可以让你使用简便但可以直接修改的语法编写代码,并会帮你处理好复制的过程。通过使用 Immer,你写出的代码看起来就像是你“打破了规则”而直接修改了对象:

immer的使用说明参考下面连接2,这里用immer重构问卷,List2.tsx代码如下:

import { FC, useState } from "react";
import { useImmer } from "use-immer";import QuestionCard from "./components/QuestionCard";
const List2: FC = () => {//列表页//问卷列表数据const questions = [{ id: "q1", title: "问卷1", isPublished: false },{ id: "q2", title: "问卷2", isPublished: false },{ id: "q3", title: "问卷3", isPublished: true },{ id: "q4", title: "问卷4", isPublished: false },{ id: "q5", title: "问卷5", isPublished: true },];const [questionList, updateQuestionList] = useImmer(questions);const r = Math.random().toString().slice(-3);// 新增问卷function add() {updateQuestionList((draft) => {draft.push({id: "q" + r,title: "问卷" + r,isPublished: false,});});}// 删除问卷function deleteQuestion(id: string) {updateQuestionList((draft) => {const index = draft.findIndex((q) => q.id === id);draft.splice(index, 1);});}// 发布问卷function publishQuestion(id: string) {updateQuestionList((draft) => {const q = draft.find((q) => q.id === id);q && (q.isPublished = true);});}return (<div><h1>问卷列表页</h1><div>{questionList.map((q) => {const { id, title, isPublished } = q;return (<QuestionCardkey={id}id={id}title={title}isPublished={isPublished}deleteQuestion={deleteQuestion}publishQuestion={publishQuestion}/>);})}</div><div><button onClick={add}>新增问卷</button></div></div>);
};export default List2;

结语

❓QQ:806797785

⭐️仓库地址:https://gitee.com/gaogzhen

⭐️仓库地址:https://github.com/gaogzhen

[1]useState[CP/OL].

[2]使用 Immer 编写简洁的更新逻辑[CP/OL].

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/74766.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端实现单点登录(SSO)的方案

概念&#xff1a;单点登录&#xff08;Single Sign-On, SSO&#xff09;主要是在多个系统、多个浏览器或多个标签页之间共享登录状态&#xff0c;保证用户只需登录一次&#xff0c;就能访问多个关联应用&#xff0c;而不需要重复登录。 &#x1f4a1; 方案分类 1. 前端级别 SS…

zabbix监控网站(nginx、redis、mysql)

目录 前提准备&#xff1a; zabbix-server主机配置&#xff1a; 1. 安装数据库 nginx主机配置&#xff1a; 1. 安装nginx redis主机配置&#xff1a; 1. 安装redis mysql主机配置&#xff1a; 1. 安装数据库 zabbix-server&#xff1a; 1. 安装zabbix 2. 编辑配置文…

无人机等非合作目标公开数据集2025.4.3

一.无人机遥感数据概述 1.1 定义与特点 在遥感技术的不断发展中&#xff0c;无人机遥感数据作为一种新兴的数据源&#xff0c;正逐渐崭露头角。它是通过无人驾驶飞行器&#xff08;UAV&#xff09;搭载各种传感器获取的地理空间信息&#xff0c;具有 覆盖范围大、综合精度高、…

大数据时代的隐私保护:区块链技术的创新应用

一、引言 在当今数字化时代&#xff0c;大数据已经成为推动社会发展的关键力量。从商业决策到社会治理&#xff0c;从医疗健康到金融服务&#xff0c;数据的价值日益凸显。然而&#xff0c;随着数据的大量收集和广泛使用&#xff0c;隐私保护问题也日益突出。如何在充分利用大…

LeetCode 2442:统计反转后的不同整数数量

目录 核心思想&#xff1a;数字的“拆分”与“重组” 分步拆解&#xff08;以输入 123 为例&#xff09; 关键操作详解 为什么能处理中间或末尾的0&#xff1f; 数学本质 总结 题目描述 解题思路 代码实现 代码解析 复杂度分析 示例演示 总结 核心思想&#xff1a;…

Python爬虫第3节-会话、Cookies及代理的基本原理

目录 一、会话和Cookies 1.1 静态网页和动态网页 1.2 无状态HTTP 1.3 常见误区 二、代理的基本原理 2.1 基本原理 2.2 代理的作用 2.3 爬虫代理 2.4 代理分类 2.5 常见代理设置 一、会话和Cookies 大家在浏览网站过程中&#xff0c;肯定经常遇到需要登录的场景。有些…

Flutter项目之登录注册功能实现

目录&#xff1a; 1、页面效果2、登录两种状态界面3、中间按钮部分4、广告区域5、最新资讯6、登录注册页联调6.1、网络请求工具类6.2、注册页联调6.3、登录问题分析6.4、本地缓存6.5、共享token6.6、登录页联调6.7、退出登录 1、页面效果 import package:flutter/material.dart…

木马学习记录

一句话木马是什么 一句话木马就是仅需要一行代码的木马&#xff0c;很简短且简单&#xff0c;木马的函数将会执行我们发送的命令 如何发送命令&#xff06;发送的命令如何执行? 有三种方式&#xff1a;GET&#xff0c;POST&#xff0c;COOKIE&#xff0c;一句话木马中用$_G…

(C语言)单链表(1.0)(单链表教程)(数据结构,指针)

目录 1. 什么是单链表&#xff1f; 2. 单链表的代码表示 3. 单链表的基本操作 3.1 初始化链表 3.2 插入结点&#xff08;头插法&#xff09; 3.3 插入结点&#xff08;尾插法&#xff09; 3.4 遍历链表 4. 单链表的优缺点 代码&#xff1a;*L(LinkList)malloc(sizeof(…

Sentinel-自定义资源实现流控和异常处理

目录 使用SphU的API实现自定义资源 BlockException 使用SentinelResource注解定义资源 SentinelResourceAspect 使用Sentinel实现限流降级等效果通常需要先把需要保护的资源定义好&#xff0c;之后再基于定义好的资源为其配置限流降级等规则。 Sentinel对于主流框架&#…

Linux信号处理解析:从入门到实战

Linux信号处理全解析&#xff1a;从入门到实战 一、初识Linux信号&#xff1a;系统级的"紧急电话" 信号是什么&#xff1f; 信号是Linux系统中进程间通信的"紧急通知"&#xff0c;如同现实中的交通信号灯。当用户按下CtrlC&#xff08;产生SIGINT信号&…

Java的Selenium的特殊元素操作与定位之select下拉框

如果页面元素是一个下拉框&#xff0c;我们可以将此web元素封装为Select对象 Select selectnew Select(WebElement element); Select对象常用api select.getOptions();//获取所有选项select.selectBylndex(index);//根据索引选中对应的元素select.selectByValue(value);//选…

蓝桥云客 刷题统计

刷题统计 问题描述 小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做 a 道题目&#xff0c;周六和周日每天做 b 道题目。请你帮小明计算&#xff0c;按照计划他将在第几天实现做题数大于等于 n 题&#xff1f; 输入格式 输入一行包含三个整数 a, b 和 …

三防笔记本有什么用 | 三防笔记本有什么特别

在现代社会&#xff0c;随着科技的不断进步&#xff0c;笔记本电脑已经成为人们工作和生活的重要工具。然而&#xff0c;在一些特殊的工作环境和极端条件下&#xff0c;普通笔记本电脑往往难以满足需求。这时&#xff0c;三防笔记本以其独特的设计和卓越的性能&#xff0c;成为…

智能体和RPA都需要程序思维,如何使用影刀的变量?

欢迎来到涛涛聊AI&#xff0c; 不管AI还是RPA&#xff0c;都需要用到编程思想才能完成批量工作。今天研究了下影刀的变量。 变量类型 根据变量值选择相应的类型&#xff0c;可选择任意一种影刀所支持的数据类型 变量值 指定变量中保存的值&#xff0c;会根据不同的类型设置…

【蓝桥杯】算法笔记3

1. 最长上升子序列(LIS) 1.1. 题目 想象你有一排数字,比如:3, 1, 2, 1, 8, 5, 6 你要从中挑出一些数字,这些数字要满足两个条件: 你挑的数字的顺序要和原来序列中的顺序一致(不能打乱顺序) 你挑的数字要一个比一个大(严格递增) 问:最多能挑出多少个这样的数字? …

性能测试之jmeter的基本使用

简介 Jmeter是Apache的开源项目&#xff0c;基于Java开发&#xff0c;主要用于进行压力测试。 优点&#xff1a;开源免费、支持多协议、轻量级、功能强大 官网&#xff1a;https://jmeter.apache.org/index.html 安装 安装步骤&#xff1a; 下载&#xff1a;进入jmeter的…

【NLP 面经 7、常见transformer面试题】

目录 1. 为何使用多头注意力机制&#xff1f; 2. Q和K使用不同权重矩阵的原因 3. 选择点乘而非加法的原因 4. Attention进行scaled的原因 5. 对padding做mask操作 6. 多头注意力降维原因 7. Transformer Encoder模块简介 8. 乘以embedding size的开方的意义 9. 位置编码 10. 其…

【深度学习】CNN简述

文章目录 一、卷积神经网络&#xff08;CNN&#xff09;二、CNN结构特性1. CNN 典型结构2. 局部连接3. 权重共享4.空间或时间上的次采样 三、理解层面 一、卷积神经网络&#xff08;CNN&#xff09; 卷积神经网络(Convolutional Neural Network&#xff0c;CNN)是一种用于处理…

理解OSPF 特殊区域NSSA和各类LSA特点

本文基于上文 理解OSPF Stub区域和各类LSA特点 在理解了Stub区域之后&#xff0c;我们再来理解一下NSSA区域&#xff0c;NSSA区域用于需要引入少量外部路由&#xff0c;同时又需要保持Stub区域特性的情况 一、 网络总拓扑图 我们在R1上配置黑洞路由&#xff0c;来模拟NSSA区域…