步入React正殿 - State进阶

目录

扩展学习资料

State进阶知识点

状态更新扩展

shouldComponentUpdate

PureComponent

为何使用不变数据【保证数据引用不会出错】

 单一数据源

 @/src/App.js

@/src/components/listItem.jsx

状态提升

 @/src/components/navbar.jsx

@/src/components/listPage.jsx

@src/App.js

有状态组件&无状态组件

Stateful【有状态】和Stateless【无状态】的区别

Stateful

Stateless

小结

练习


扩展学习资料

预习资料名称 

链接

备注

不可变数据

https://github.com/immutable-js/immutable-js

JS内存管理

内存管理 - JavaScript | MDN

状态提升

mangojuice.top - 该网站正在出售! - mangojuice 资源和信息。

扩展阅读

context管理状态

http://react.html.cn/docs/context.html  

聊一聊我对 React Context 的理解以及应用 - 掘金

扩展阅读

State进阶知识点

  • 通过条件判断优化渲染
  • 使用不可变数据
  • 状态提升
  • 使用无状态组件

状态更新扩展

阻止不必要的render方法执行

shouldComponentUpdate

// render渲染执行前调用的函数,返回false,可以有效的阻止不必要的render方法执行shouldComponentUpdate(nextProps, nextState) {console.log('props', this.props, nextProps);console.log('state', this.state, nextState);if(this.state.count === nextState.count) {return false}if(this.props.id === nextProps.id) {return false}return true}

PureComponent

import React, { PureComponent } from 'react';
class ListItem extends PureComponent {}

为何使用不变数据【保证数据引用不会出错】

// ...
handleDelete = (id) => {// 使用不可变数据, filter返回一个新数组const listData = this.state.listData.filter((item) => item.id !== id);this.setState({listData,});};handleAmount = () => {// 如不使用新的数组【没有使用不可变数据】, state变化,不会重新渲染UI//const _list = this.state.listData.concat([]);/* pop() 方法用于删除数组的最后一个元素并返回删除的元素。注意:此方法改变数组的长度!提示: 移除数组第一个元素,请使用 shift() 方法。*/_list.pop();this.setState({listData: _list,});};
// ...

如下图,如果没有创建新的引用,在PureComponent中,不会调用render

 如下图,使用不可变数据,可以避免引用带来的副作用,使得整个程序数据变的易于管理

 单一数据源

handleReset = () => {// 使用map方法创建一个新的数组const _list = this.state.listData.map((item) => {// ... 解构符const _item = { ...item };_item.value = 0;return _item;});this.setState({listData: _list,});// 此时props数据变化,子组件state.count没变化// 原因出在没有使用单一数据源};

 @/src/App.js

import React, { PureComponent } from 'react';
import ListItem from './components/listItem';
import ListItemFunc from './components/listItemFunc';
import style from './components/listitem.module.css';// eslint-disable-next-line no-unused-vars
class App extends PureComponent {constructor(props) {super(props);this.state = {listData: [{id: 1,name: 'sony 65寸高清电视',price: 4000,stock: 1,value: 4,},{id: 2,name: '华为 Meta30',price: 6000,stock: 12,value: 2,},{id: 3,name: '华硕 玩家国度笔记本',price: 10000,stock: 11,value: 1,}],};}renderList() {return this.state.listData.map((item) => {return (<ListItemkey={item.id}data={item}onDelete={this.handleDelete}onDecrease={this.handleDecrease}onAdd={this.handleAdd}/>);});}handleDelete = (id) => {// 使用不可变数据, filter返回一个新数组const listData = this.state.listData.filter((item) => item.id !== id);this.setState({listData,});};handleDecrease = (id) => {// 使用不可变数据, filter返回一个新数组const _data = this.state.listData.map((item) => {if (item.id === id) {const _item = { ...item };_item.value--;if (_item.value < 0) _item.value = 0;return _item;}return item;});this.setState({listData: _data,});};handleAdd = (id) => {// 使用不可变数据, filter返回一个新数组console.log(id);const _data = this.state.listData.map((item) => {if (item.id === id) {const _item = { ...item };_item.value++;return _item;}return item;});this.setState({listData: _data,});};handleAmount = () => {// 如不使用新的数组【没有使用不可变数据】, state变化,不会重新渲染UI//const _list = this.state.listData.concat([]);/* pop() 方法用于删除数组的最后一个元素并返回删除的元素。注意:此方法改变数组的长度!提示: 移除数组第一个元素,请使用 shift() 方法。*/_list.pop();this.setState({listData: _list,});};handleReset = () => {// 使用map方法创建一个新的数组const _list = this.state.listData.map((item) => {// ... 结构符const _item = { ...item };_item.value = 0;return _item;});this.setState({listData: _list,});// 此时props数据变化,子组件state.count没变化// 原因出在没有使用单一数据源};render() {return (<div className='container'><button onClick={this.handleAmount} className='btn btn-primary'>减去最后一个</button><button onClick={this.handleReset} className='btn btn-primary'>重置</button>{this.state.listData.length === 0 && (<div className='text-center'>购物车是空的</div>)}{this.renderList()}</div>);}
}export default App;

@/src/components/listItem.jsx

// import React, { Component } from 'react';
import React, { PureComponent } from 'react';
import style from './listitem.module.css';
import classnames from 'classnames/bind';
const cls = classnames.bind(style);
class ListItem extends PureComponent {// 类的构造函数// eslint-disable-next-line no-useless-constructorconstructor(props) {super(props);} render() {console.log('item is rendering');return (<div className='row mb-3'><div className='col-4 themed-grid-col'><span style={{ fontSize: 22, color: '#710000' }}>{this.props.data.name}</span></div><div className='col-1 themed-grid-col'><span className={cls('price-tag')}>¥{this.props.data.price}</span></div><divclassName={`col-2 themed-grid-col${this.props.data.value ? '' : '-s'}`}><buttononClick={() => {this.props.onDecrease(this.props.data.id);}}type='button'className='btn btn-primary'>-</button><span className={cls('digital')}>{this.props.data.value}</span><buttononClick={() => {this.props.onAdd(this.props.data.id);}}type='button'className='btn btn-primary'>+</button></div><div className='col-2 themed-grid-col'>¥ {this.props.data.price * this.props.data.value}</div><div className='col-1 themed-grid-col'><buttononClick={() => {this.props.onDelete(this.props.data.id);}}type='button'className='btn btn-danger btn-sm'>删除</button></div></div>);}
}
export default ListItem;

状态提升

处理组件和子组件数据传递,自顶向下单向流动

 @/src/components/navbar.jsx

import React, { PureComponent } from 'react';
class Nav extends PureComponent {render() {return (<nav className='navbar navbar-expand-lg navbar-light bg-light'><div className='container'><div className='wrap'><span className='title'>NAVBAR</span><span className='badge badge-pill badge-primary ml-2 mr-2'>{this.props.itemNum}</span><buttononClick={this.props.onReset}className='btn btn-outline-success my-2 my-sm-0 fr'type='button'>Reset</button></div></div></nav>);}
}
export default Nav;

@/src/components/listPage.jsx

import React, { PureComponent } from 'react';
import ListItem from './listItem.jsx';
// 商品列表渲染
class ListPage extends PureComponent {renderList() {return this.props.data.map((item) => {return (<ListItemkey={item.id}data={item}onDelete={this.props.handleDelete}onDecrease={this.props.handleDecrease}onAdd={this.props.handleAdd}/>);});}render() {return (<div className='container'>{this.props.data.length === 0 && (<div className='text-center'>购物车是空的</div>)}{this.renderList()}</div>);}
}
export default ListPage;

@src/App.js

import React, { PureComponent } from 'react';
import Nav from './components/navbar';
import ListPage from './components/listPage';
const listData = [{id: 1,name: 'sony 65寸高清电视',price: 4000,stock: 1,value: 4,},{id: 2,name: '华为 Meta30',price: 6000,stock: 12,value: 2,},{id: 3,name: '华硕 玩家国度笔记本',price: 10000,stock: 11,value: 1,},
];
// eslint-disable-next-line no-unused-vars
class App extends PureComponent {constructor(props) {super(props);this.state = {listData: listData,};}handleDelete = (id) => {// 使用不可变数据, filter返回一个新数组const listData = this.state.listData.filter((item) => item.id !== id);this.setState({listData,});};handleDecrease = (id) => {// 使用不可变数据, filter返回一个新数组const _data = this.state.listData.map((item) => {if (item.id === id) {const _item = { ...item };_item.value--;if (_item.value < 0) _item.value = 0;return _item;}return item;});this.setState({listData: _data,});};handleAdd = (id) => {// 使用不可变数据, filter返回一个新数组console.log(id);const _data = this.state.listData.map((item) => {if (item.id === id) {const _item = { ...item };_item.value++;return _item;}return item;});this.setState({listData: _data,});};handleAmount = () => {// 如不使用新的数组【没有使用不可变数据】, state变化,不会重新渲染UI//const _list = this.state.listData.concat([]);/* pop() 方法用于删除数组的最后一个元素并返回删除的元素。注意:此方法改变数组的长度!提示: 移除数组第一个元素,请使用 shift() 方法。*/_list.pop();this.setState({listData: _list,});};handleReset = () => {// 使用map方法创建一个新的数组const _list = this.state.listData.map((item) => {// ... 结构符const _item = { ...item };_item.value = 0;return _item;});this.setState({listData: _list,});// 此时props数据变化,子组件state.count没变化// 原因出在没有使用单一数据源};render() {return (<><Nav itemNum={this.state.listData.length} onReset={this.handleReset} /><ListPagedata={this.state.listData}handleAdd={this.handleAdd}handleAmount={this.handleAmount}handleDecrease={this.handleDecrease}handleDelete={this.handleDelete}handleReset={this.handleReset}/></>);}
}
export default App;

有状态组件&无状态组件

Stateful【有状态】和Stateless【无状态】的区别

Stateful

  • 类组件
  • 有状态组件
  • 容器组件

Stateless

  • 函数组件
  • 无状态组件
  • 展示组件

尽可能通过状态提升原则,将需要的状态提取到父组件中,而其他的组件使用无状态组件编写【父组件有状态,子组件无状态】

无状态组件简单好维护,单一从上而下的数据流

小结

  • 优化渲染
  • 使用不可变数据
  • 单一数据源以及状态提升
  • 无状态组件写法

练习

【题目1】 用单一数据源原则和状态提升原则改造购物车工程

【题目2】 目前Header中显示的是商品种类数量,改造成商品的总数目

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

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

相关文章

reeds_sheep运动规划算法Python源码分析

本文用于记录Python版本zhm-real / PathPlanning运动规划库中reeds_sheep算法的源码分析 关于reeds sheep算法的原理介绍前文已经介绍过了&#xff0c;链接如下所示&#xff1a; 《Reeds-Shepp曲线学习笔记及相关思考》 《Reeds-Shepp曲线基础运动公式推导过程》 正文&#xff…

防丢器Airtag国产版

Airtag是什么&#xff1f; AirTag是苹果公司设计的一款定位神奇&#xff0c;它通过一款纽扣电池进行供电&#xff0c;即可实现长达1-2年的关键物品的定位、查找的功能。 按照苹果公司自己的话说—— 您“丢三落四这门绝技&#xff0c;要‍失‍传‍了”。 AirTag 可帮你轻松追…

阿里云与中国中医科学院合作,推动中医药行业数字化和智能化发展

据相关媒体消息&#xff0c;阿里云与中国中医科学院的合作旨在推动中医药行业的数字化和智能化发展。随着互联网的进步和相关政策的支持&#xff0c;中医药产业受到了国家的高度关注。这次合作将以“互联网 中医药”为载体&#xff0c;致力于推进中医药文化的传承和创新发展。…

2023最新红盟云卡个人自动发卡系统源码 全开源

​ 简介&#xff1a; 2023最新红盟云卡个人自动发卡系统源码 全开源 该系统完全开源且无任何加密&#xff0c;可商业使用&#xff0c;并支持个人免签多个接口。 ​ 图片&#xff1a;

总结,由于顺丰的问题,产生了电脑近期一个月死机问题集锦

由于我搬家&#xff0c;我妈搞顺丰发回家&#xff0c;但是没有检查有没有坏&#xff0c;并且我自己由于不可抗力因素&#xff0c;超过了索赔时间&#xff0c;反馈给顺丰客服&#xff0c;说超过了造成了无法索赔的情况&#xff0c;现在总结发生了损坏配件有几件&#xff0c;显卡…

成集云 | 鼎捷ERP采购单同步钉钉 | 解决方案

源系统成集云目标系统 方案介绍 鼎捷ERP&#xff08;Enterprise Resource Planning&#xff09;是一款综合性的企业管理软件&#xff0c;它包括了多个模块来管理企业的各个方面&#xff0c;其中之一就是采购订单模块。鼎捷ERP的采购订单模块可以帮助企业有效管理和控制采购过程…

Java 项目日志实例基础:Log4j

点击下方关注我&#xff0c;然后右上角点击...“设为星标”&#xff0c;就能第一时间收到更新推送啦~~~ 介绍几个日志使用方面的基础知识。 1 Log4j 1、Log4j 介绍 Log4j&#xff08;log for java&#xff09;是 Apache 的一个开源项目&#xff0c;通过使用 Log4j&#xff0c;我…

从零开始学习 Java:简单易懂的入门指南之Objects、BigInteger、BigDecimal(十四)

常用API&#xff0c;Objects、BigInteger、BigDecimal 5 Objects类5.1 概述5.2 常见方法 6 BigInteger类6.1 引入6.2 概述6.3 常见方法6.4 底层存储方式&#xff1a; 7 BigDecimal类7.1 引入7.2 概述7.3 常见方法7.4 底层存储方式&#xff1a; 5 Objects类 5.1 概述 tips&…

Tesla Model S 3对比分析拆解图

文章来源&#xff1a;网络 需要特斯拉电驱样件的请&#xff1a;shbinzer &#xff08;拆车邦&#xff09; 5 款电机&#xff0c;其中扁线永磁同步电机最大功率从 202kW 提升至 220kW&#xff0c;最大扭矩从 404Nm提升至 440Nm。 Model S/X→Model 3/Y&#xff1a;双电机版本…

使用SpringBoot + Thymeleaf 完成简单的用户登录

&#x1f600;前言 本篇博文是关于Thymeleaf 的综合案例&#xff0c; 使用SpringBoot Thymeleaf 完成简单的用户登录-列表功能&#xff0c;希望你能够喜欢&#x1f60a; &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨…

PyTorch训练深度卷积生成对抗网络DCGAN

文章目录 DCGAN介绍代码结果参考 DCGAN介绍 将CNN和GAN结合起来&#xff0c;把监督学习和无监督学习结合起来。具体解释可以参见 深度卷积对抗生成网络(DCGAN) DCGAN的生成器结构&#xff1a; 图片来源&#xff1a;https://arxiv.org/abs/1511.06434 代码 model.py impor…

win系统部署Apollo-quick-start-2.1.0

win系统部署Apollo-quick-start-2.1.0 携程Apollo配置中心&#xff0c;官方部署包里提供了2个sql文件&#xff0c;需要刷入数据库。之后修改demo.sh里的数据库配置,最后使用git bash启动demo.sh刷sql脚本 官方部署包里提供了2个sql文件 修改demo.sh文件 使用git bash启动demo…

WinCC V7.5 中的C脚本对话框不可见,将编辑窗口移动到可见区域的具体方法

WinCC V7.5 中的C脚本对话框不可见&#xff0c;将编辑窗口移动到可见区域的具体方法 由于 Windows 系统更新或使用不同的显示器&#xff0c;在配置C动作时&#xff0c;有可能会出现C脚本编辑窗口被移动到不可见区域的现象。 由于该窗口无法被关闭&#xff0c;故无法进行进一步…

安防监控视频云存储EasyCVR平台H.265转码功能更新:新增分辨率配置

安防视频集中存储EasyCVR视频监控综合管理平台可以根据不同的场景需求&#xff0c;让平台在内网、专网、VPN、广域网、互联网等各种环境下进行音视频的采集、接入与多端分发。在视频能力上&#xff0c;视频云存储平台EasyCVR可实现视频实时直播、云端录像、视频云存储、视频存储…

微服务中间件-分布式缓存Redis

分布式缓存 a.Redis持久化1) RDB持久化1.a) RDB持久化-原理 2) AOF持久化3) 两者对比 b.Redis主从1) 搭建主从架构2) 数据同步原理&#xff08;全量同步&#xff09;3) 数据同步原理&#xff08;增量同步&#xff09; c.Redis哨兵1) 哨兵的作用2) 搭建Redis哨兵集群3) RedisTem…

小程序的数据绑定和事件绑定

小程序的数据绑定 1.需要渲染的数据放在index.js中的data里 Page({data: {info:HELLO WORLD,imgSrc:/images/1.jpg,randomNum:Math.random()*10,randomNum1:Math.random().toFixed(2)}, }) 2.在WXML中通过{{}}获取数据 <view>{{info}}</view><image src"{{…

设计模式之责任链模式

简介 责任链模式是一种行为设计模式&#xff0c; 允许你将请求沿着处理者链&#xff08;单向链表&#xff09;进行发送。 收到请求后&#xff0c; 每个处理者根据自身条件对请求进行处理&#xff0c; &#xff0c;如果处理不了则将其传递给链上的下个处理者&#xff0c;以此类…

【LVS】3、LVS+Keepalived群集

为什么用它&#xff0c;为了做高可用 服务功能 1.故障自动切换 2.健康检查 3.节点服务器高可用-HA Keepalived的三个模块&#xff1a; core&#xff1a;Keepalived的核心&#xff0c;负责主进程的启动、维护&#xff1b;调用全局配置文件进行加载和解析 vrrp&#xff1a;实…

5个高清视频素材网站

推荐5个高清视频素材网站&#xff0c;免费、付费、商用的都有&#xff0c;可根据自己需求去选择&#xff0c;赶紧收藏吧&#xff01; 菜鸟图库 https://www.sucai999.com/video.html?vNTYxMjky ​ 菜鸟图库网素材非常丰富&#xff0c;网站主要还是以设计类素材为主&#xff…

Spring-Bean的生命周期

目录 生命周期汇总 细分生命周期 1.实例化 2.属性赋值&#xff08;依赖注入&#xff09; 3.Aware接口 4.BeanPostProcessor接口 5.初始化 6.销毁 测试验证 类结构 业务类 测试类 生命周期汇总 Spring Bean 的生命周期见下图 &#xff08;一定记忆好下图&#x…