【React】03-关于React state(状态) 的实践

背景

在学习React组件的过程中,发现state的运用很广泛,但对于它的使用及运行机制还是比较模凌两可的,故找了一些资料学习一下。

实践

React中的组件类型被分为了两类:函数组件,又被称为无状态组件;类组件,又被称为有状态组件。状态(state)即数据。函数组件没有自己的状态,自负责数据展示。类组件有自己的状态,负责更新UI。React中想要实现该功能,就要使用类组件(有状态组件)。随着React的发展,在React 16.8之后,引入了Hooks,函数组件也可以开始使用状态,如下例子:

// 函数式组件中使用 useState Hook
import React, { useState } from 'react';function ExampleComponent() {const [count, setCount] = useState(0);return (<div><p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>Click me</button></div>);
}

而对于有状态组件(类组件),我们通常在constructor中定义state,通过this.setState()去修改,react会自动帮我们合并state中未修改的部分。

import React from "react";class Clock extends React.Component {constructor(props) {super(props);this.timer = null;this.state = {currentTime: new Date()};}componentDidMount() {this.timer = setInterval(() => {this.setState({currentTime: new Date()});}, 5000);}componentWillUnmount() {clearInterval(this.timer);}render() {const { currentTime } = this.state;return (<div><p>currentTime: {currentTime.toLocaleTimeString()}</p></div>);}}export default Clock;

注意! 当我们调用this.setState(),组件会调用render方法重新渲染页面而直接去修改state,而直接修改不会重新渲染组件,在官方文档描述里也不推荐这种做法。因为它可能导致 React 无法正确地进行状态追踪和组件的重新渲染。

另一方面,state的更新可能会被合并,当你连续多次调用this.setState()的时候,出于性能考虑,react会将多次合并为一次更新,这导致了state的更新可能是异步的,所以当我们修改state的时候不应该依赖旧的state(为了解决这个问题,setState也支持传入一个函数接受最新的props和state)。

// 错误姿势
this.setState({counter: this.state.counter + this.props.increment,
});
// 正确姿势
this.setState((state, props) => ({counter: state.counter + props.increment
}));

最佳实践

这里主要罗列了React社区提出了一些最佳实践方式:

  1. 状态提升(Lifting State Up): 当多个组件共享状态时,将状态提升到这些组件的最近共同父组件是一种良好的实践。这样可以避免状态的不一致性和复杂性。

    例如一个简单的购物车应用。我们将创建两个组件:ProductListShoppingCartProductList 显示可供购买的商品列表,而 ShoppingCart 显示已选商品和计算总价。我们将使用状态提升来管理选购商品的状态。那么我们可以考虑如下代码:
    在这个例子中,ProductList 组件管理商品列表和已选商品的状态。当用户点击 “Add to Cart” 按钮时,通过回调函数 handleProductSelect 更新状态,并将选购的商品传递给 ShoppingCart 组件。通过这种方式,ShoppingCart 组件通过 props 获取所需的状态,并显示已选商品和计算总价。这样两个组件通过 state 提升的方式共享了选购商品的状态。

// 商品列表组件
class ProductList extends React.Component {state = {products: [{ id: 1, name: 'Product A', price: 20 },{ id: 2, name: 'Product B', price: 30 },{ id: 3, name: 'Product C', price: 40 }],selectedProducts: []};handleProductSelect = (productId) => {const selectedProduct = this.state.products.find(product => product.id === productId);this.setState(prevState => ({selectedProducts: [...prevState.selectedProducts, selectedProduct]}));}render() {return (<div><h2>Product List</h2><ul>{this.state.products.map(product => (<li key={product.id}>{product.name} - ${product.price}<button onClick={() => this.handleProductSelect(product.id)}>Add to Cart</button></li>))}</ul><ShoppingCart selectedProducts={this.state.selectedProducts} /></div>);}
}// 购物车组件
class ShoppingCart extends React.Component {calculateTotalPrice = () => {return this.props.selectedProducts.reduce((total, product) => total + product.price, 0);}render() {return (<div><h2>Shopping Cart</h2><ul>{this.props.selectedProducts.map(product => (<li key={product.id}>{product.name} - ${product.price}</li>))}</ul><p>Total Price: ${this.calculateTotalPrice()}</p></div>);}
}// 应用根组件
class App extends React.Component {render() {return (<div><ProductList /></div>);}
}
  1. 用状态容器库: 对于大型应用,可以考虑使用状态容器库(如Redux、MobX)来集中管理应用的状态。这样可以更好地组织和分离关注点,使得应用的状态变得更加可维护。

    关于状态容器库,其实就像Java里封装好的函数方法或者jar包。在前端开发中,状态容器通常用于管理全局状态,使得多个组件能够方便地访问和共享相同的状态数据。以Redux为例子,它通过单一的不可变状态树来管理整个应用的状态,并使用纯函数来执行状态的变更。

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

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

相关文章

1*2*3+3*4*5+...+99*100*101python,1加到100的程序算法python

大家好&#xff0c;本文将围绕python中123一直加到100程序怎么写展开说明&#xff0c;计算123456...100的值python是一个很多人都想弄明白的事情&#xff0c;想搞清楚计算1-23-45 … -100的值python需要先了解以下几个事情。 今天下午上python课的时候&#xff0c;老师留了一个…

python基础教程二(列表相关知识)

列表 列表定义及其相关内置函数 列表类似一个可以改变的数组&#xff0c;里边的类型不同于c&#xff0c;c要求类型必须相同&#xff0c;列表的元素任意类型都可以&#xff0c;最重要的是列表可以改变&#xff0c;和元组和字符串最大区别 list函数&#xff1a;将别的序列元素变…

佳能G3800彩色喷墨多功能一体打印机报5B00错误代码处理方法

5B00错误代码的含义 5B00错误代码是指佳能G3800打印机的“废墨仓已满”。这个废墨仓是打印机内部的一个部件&#xff0c;主要用于收集打印过程中产生的废墨。当废墨仓已满时&#xff0c;打印机就会报5B00错误代码。 佳能G3800彩色喷墨多功能一体打印机报5B00错误代码处理办法 …

大数据 MapReduce是什么?

在Hadoop问世之前&#xff0c;其实已经有了分布式计算&#xff0c;只是那个时候的分布式计算都是专用的系统&#xff0c;只能专门处理某一类计算&#xff0c;比如进行大规模数据的排序。 很显然&#xff0c;这样的系统无法复用到其他的大数据计算场景&#xff0c;每一种应用都…

大数据技术与应用开发赛项笔记

各种启动命令 修改mysql数据库编码&#xff1a;alter database shtd_result CHARACTER SET utf8; hadoop : start-all.sh hive服务&#xff1a; hive --service metastore hive 客户端 &#xff1a;hive dolphinscheduler服务&#xff1a;./bin/dolphinscheduler-daemon.sh sta…

【算法刷题】## 算法题目第1讲:双指针处理数组题目 带视频讲解

算法题目第一讲&#xff1a;双指针处理数组题目 解决力扣&#xff1a; [344. 反转字符串][167. 两数之和 II - 输入有序数组][26. 删除有序数组中的重复项][27. 移除元素][283. 移动零][5. 最长回文子串] 配合b站视频讲解食用更佳:https://www.bilibili.com/video/BV1vW4y1P…

傻傻”的JAVA编译器

故事是从一个问题开始的&#xff1a;为什么 Java 中 2 * (i * i) 比 2 * i * i更快&#xff1f; 猛地一看&#xff0c;我还以为有人在钓鱼&#xff0c;这俩玩意不应该是一模一样吗&#xff1f;第二反应是计算结果溢出了int值所以导致了这个差异&#xff0c;于是我掏出JMH这个利…

什么是系统设计 – 学习系统设计

系统设计被定义为为系统的不同组件、接口和模块创建架构并提供有助于在系统中实现这些元素的相应数据的过程。系统设计是任何分布式系统设计背后的核心概念。 系统设计涉及识别数据源&#xff0c;它是描述、创建和规划框架以满足特定业务的必要性和先决条件的直觉。 为什么要…

excel公式名称管理器

1.问题 在日常使用excel的时候&#xff0c;发布一个表格文件&#xff0c;需要限制表格的某列或某行只能从我们提供的选项中选择&#xff0c;自己随便填写视为无效&#xff0c;如下图所示&#xff0c;上午的行程安排只能从"在岗"、"出差"、"病假"…

java面试汇总

JVM内存模型与Java线程内存模型的区别 JVM内存模型描述的是Java虚拟机在执行Java程序时如何管理和使用内存&#xff0c;主体围绕&#xff1a;方法区&#xff08;Method Area&#xff09;、堆&#xff08;Heap&#xff09;、程序计数器&#xff08;Program Counter Register&am…

AI绘图模型不会写字的难题解决了

介绍 大家好&#xff0c;最近有个开源项目比较有意思&#xff0c;解决了图像中不支持带有中文的问题。 https://github.com/tyxsspa/AnyText。 为什么不能带有中文&#xff1f; 数据集局限 Stable Diffusion的训练数据集以英文数据为主&#xff0c;没有大量包含其他语言文本的…

LeetCode-141环形链表 LeetCode-142环形链表二

一、前言 本篇文章在我之前讲完的链表、链表与递归的基础上进行讲解&#xff0c;本次我们以leetcode为例&#xff0c;讲解链表的其他题型&#xff0c;今天我们先了解一下环形链表&#xff0c;这里我们以leetCode141和leetCode142为例。 二、LeetCode141 首先关于这道题&#…

微服务注册中心之Eureka

微服务注册中心之Eureka eureka 搭建集群 版本说明 Spring Boot 2.1.7.RELEASE spring-cloud-starter-netflix-eureka-server Finchley.SR2 spring-boot-starter-security 2.1.7.RELEASE pom.xml 文件 <?xml version"1.0" encoding"UTF-8"?> &l…

游戏缺少emp.dll详细修复教程,快速解决游戏无法启动问题

在现代游戏中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“emp.dll丢失”。emp.dll是一个动态链接库文件&#xff0c;它包含了许多程序运行所需的函数和数据。当一个程序需要调用这些函数时&#xff0c;系统会从emp.dll文件中加载相应的内容。因此&#x…

VSCode上远程调试代码出现的问题

记录一下&#xff1a; 真的是汗流浃背了&#xff0c;师妹叫帮忙如何在VSCode上远程调试代码&#xff0c;一些自己已经经历过的问题&#xff0c;现在已经忘记了。又在网上一顿搜索&#xff0c;这次记录下吧。。。 出现以下问题&#xff1a; 1. 终端界面总是sh-4.4 $ &#xff…

【每日试题】java面试题之中间件

什么是中间件&#xff1f; 中间件是指位于客户端和服务器之间的一层软件&#xff0c;它可以提供一系列的服务&#xff0c;简化了开发和管理复杂的分布式应用系统。 中间件的分类有哪些&#xff1f; 中间件可以分为消息中间件、缓存中间件、数据访问中间件、分布式计算中间件、…

LINUX加固之命令审计

一、前言 在LINUX安全范畴中&#xff0c;安全溯源也是很重要的一个环节。对主机上所有曾操作过的命令详细信息需要有一份记录保存&#xff0c;当系统遭受破坏或者入侵&#xff0c;拿出这份记录&#xff0c;可以帮助定位一些可疑动作。 很多系统通常都会配置安全堡垒机&#xff…

jmeter断言-三种

1.响应断言 substring是指包含就行 不用完全相等 2.json断言 3.持续时间断言

Consule安装与SpringBoot集成

Consule Consul 是由 HashiCorp 开发的一款软件工具&#xff0c;提供了一组功能&#xff0c;用于服务发现、配置管理和网络基础设施自动化。它旨在帮助组织管理现代分布式和微服务架构系统的复杂性。以下是Consul的一些关键方面和功能&#xff1a; 服务发现&#xff1a;Consul…

JS常用数据类型转换

js提供了5中基本数据类型&#xff1a;数字 number 字符串 string 布尔 boolean 空值 null 未定义的 undefined 常用的是数字型和字符串型之间的转换&#xff0c;常用的转换方法如下&#xff1a; 1 数字型转换成字符串型 a) 使用String&#xff08;&#xff09;方…