步入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.hqwc.cn/news/74017.html

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

相关文章

解析TCP/IP协议的分层模型

了解ISO模型&#xff1a;构建通信的蓝图 为了促进网络应用的普及&#xff0c;国际标准化组织&#xff08;ISO&#xff09;引入了开放式系统互联&#xff08;Open System Interconnect&#xff0c;OSI&#xff09;模型。这个模型包括了七个层次&#xff0c;从底层的物理连接到顶…

mysql的两张表left join 进行关联后,索引进行优化案例

一 mysql的案例 1.1 不加索引情况 1.表1没加索引 2.表2没加索引 3.查看索引 1.2 添加索引 1.表1添加索引 2.表2添加索引 3.查看

爬虫逆向实战(五)--猿人学第三题

一、数据接口分析 主页地址&#xff1a;猿人学第三题 1、抓包 通过抓包可以发现数据接口是api/match/3 2、判断是否有加密参数 请求参数是否加密&#xff1f; 无请求头是否加密&#xff1f; 无响应是否加密&#xff1f; 无cookie是否加密&#xff1f; 无 二、发送请求 …

计算机 数进制转换;存储MB与带宽Mbps

参考&#xff1a;https://zhuanlan.zhihu.com/p/459817484 1、计算机 数进制转换 1&#xff09;与十进制相关的转换 2&#xff09;与二进制相关的转换 二进制是Binary&#xff0c;简写为B&#xff1b;八进制是Octal&#xff0c;简写为O&#xff1b;十进制是Decimal&#xff…

【java毕业设计】基于ssm+mysql+jsp的大学生兼职信息系统设计与实现(程序源码)-大学生兼职信息系统

基于ssmmysqljsp的大学生兼职信息系统设计与实现&#xff08;程序源码毕业论文&#xff09; 大家好&#xff0c;今天给大家介绍基于ssmmysqljsp的大学生兼职信息系统设计与实现&#xff0c;本论文只截取部分文章重点&#xff0c;文章末尾附有本毕业设计完整源码及论文的获取方式…

万字长文·通俗易懂·一篇包掌握——输入/输出·文件操作(c语言超详细系列)(二)

前言&#xff1a;Hello&#xff0c;大家好&#x1f618;&#xff0c;我是心跳sy&#xff0c;上一节我们主要学习了格式化输入输出的基本内容&#xff0c;这一节我们对格式化进行更加深入的了解&#xff0c;对文件概念进行介绍&#xff0c;并且对输入、输出与文件读写的基本概念…

商城-学习整理-高级-性能压测缓存问题(十一)

目录 一、基本介绍1、性能指标2、JMeter1、JMeter 安装2、JMeter 压测示例1、添加线程组2、添加 HTTP 请求3、添加监听器4、启动压测&查看分析结果 3、JMeter Address Already in use 错误解决 二、性能监控1、jvm 内存模型2、堆3、jconsole 与 jvisualvm1、jvisualvm 能干…

文心一言最新重磅发布!

8月16日&#xff0c;由深度学习技术及应用国家工程研究中心主办的WAVE SUMMIT深度学习开发者大会2023举办。百度首席技术官、深度学习技术及应用国家工程研究中心主任王海峰以《大语言模型为通用人工智能带来曙光》为题&#xff0c;阐述了大语言模型具备理解、生成、逻辑、记忆…

AIGC绘画:基于Stable Diffusion进行AI绘图

文章目录 AIGC深度学习模型绘画系统stable diffusion简介stable diffusion应用现状在线网站云端部署本地部署Stable Diffusion AIGC深度学习模型绘画系统 stable diffusion简介 Stable Diffusion是2022年发布的深度学习文本到图像生成模型&#xff0c;它主要用于根据文本的描述…

Qt扫盲- Graphics View框架理论综述

Graphics View框架理论综述 一、概述二、Graphics View 体系结构1. The Scene2. The View3. 图元 Item 三、图形视图坐标系统1. 图元Item的坐标2. Scene Scene坐标3. View 视图坐标4. 坐标映射 四、关键特性1. 缩放和旋转2. 打印3. 拖放4. 鼠标指针和 提示5. 动画6. OpenGL渲染…

【手写数据库toadb 造不一样的轮子】行列混合存储模型 就是为大模型分析准备的

行列混合存储模型 ​专栏内容: postgresql内核源码分析手写数据库toadb并发编程个人主页:我的主页 座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物. 概述 混合模型的由来 我们虽然造轮子,但是也会造完全一样的轮子。所以toadb在选择存储模型时,行存模型已经成熟…

Day978.如何在移动App中使用OAuth 2.0? -OAuth 2.0

如何在移动App中使用OAuth 2.0&#xff1f; Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于如何在移动App中使用OAuth 2.0&#xff1f;的内容。 除了 Web 应用外&#xff0c;现实环境中还有非常多的移动 App。 那么&#xff0c;在移动 App 中&#xff0c;能不能使…