步入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.pswp.cn/news/43276.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/43276.shtml
英文地址,請注明出處:http://en.pswp.cn/news/43276.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Uniapp連接藍牙設備

一、效果圖 二、流程圖 三、實現 UI <uni-list><uni-list :border="true"><!-- 顯示圓形頭像 -->

C語言案例 判斷是否為回文數-06.1

題目&#xff1a;隨機輸入一個5位數&#xff0c;判斷它是不是回文數 步驟一&#xff1a;定義程序的目標 編寫C程序&#xff0c;隨機輸入一個5位數&#xff0c;判斷它是不是回文數 步驟二&#xff1a;程序設計 原理&#xff1a;即12321是回文數&#xff0c;個位與萬位相同&#…

SpringBoot + Vue 微人事(十)

職位管理前后端接口對接 先把table中的數據展示出來&#xff0c;table里面的數據實際上是positions里面的數據&#xff0c;就是要給positions:[] 賦上值 可以在methods中定義一個initPosition方法 methods:{//定義一個初始化positions的方法initPositions(){//發送一個get請求…

2.HTML、CSS

文章目錄 1.什么是HTML、CSS2.HTML的語法特點3.HTML的快速體驗4.開發工具推薦&#xff1a;VS Code5.基本標簽&樣式5.1.標題5.1.1.標題排版5.1.2.標題樣式5.1.3.超鏈接 5.2.正文5.2.1.正文排版5.2.2.頁面布局 表格、表單標簽表格標簽表單標簽 1.什么是HTML、CSS HTML即超文本…

在vue中如何重新渲染所有組件

文章目錄 一、在根組件中給router-view動態綁定上v-if。二、調用重新加載下級組件方法。 在有些需求情況下需要重新加載頁面或者觸發組件的生命周期&#xff0c;但是刷新對用戶體驗不太友好&#xff0c;這個時候我們可以通過provide/inject可以輕松實現跨級訪問祖先組件的數據&…

web JS高德地圖標點、點聚合、自定義圖標、自定義窗體信息、換膚等功能實現和高復用性組件封裝教程

文章目錄 前言一、點聚合是什么&#xff1f;二、開發前準備三、API示例1.引入高德地圖2.創建地圖實例3.添加標點4.刪除標點5.刪除所有標點&#xff08;覆蓋物&#xff09;6.聚合點7.自定義聚合點樣式8.清除聚合9.打開窗體信息 四、實戰開發需求要求效果圖如下&#xff1a;封裝思…

LeetCode1387 將整數按權重排序

思路 首先是這種計算權重的方式很有可能出現重復&#xff0c;所以需要記憶化搜索記憶化搜索&#xff1a;先查表再計算&#xff0c;先存表再返回。將整數 x 和計算的權重分別存儲數組的0和1的位置重寫compare將數組排序按規則排序返回結果 代碼 class Solution {private Hash…

(二)Git在公司中團隊內合作和跨團隊合作和分支操作的全部流程(一篇就夠)

&#xff08;一&#xff09;Git連接GitHub的全部流程https://blog.csdn.net/m0_65992672/article/details/132333727 團隊內協作 項目經理通過git push將代碼推送到遠程倉庫【也就是git、gitee等代碼托管中心】,推完以后組員可以通過git clone克隆下來代碼&#xff0c;如果組…

redis主從復制

隨著項目訪問量的增加&#xff0c;對Redis服務器的操作也越加頻繁&#xff0c;雖然Redis讀寫速度都很快&#xff0c;但是一定程度上也會造成一定的延時&#xff0c;那么為了解決訪問量大的問題&#xff0c;通常會采取的一種方式是主從架構Master/Slave&#xff0c;Master 以寫為…

3.react useRef使用與常見問題

react useRef使用與常見問題 文章目錄 react useRef使用與常見問題1. Dom操作: useRef()2. 函數組件的轉發: React.forwardRef()3. 對普通值進行記憶, 類似于一個class的實例屬性4. 結合useEffect,只在更新時觸發FAQ 1. Dom操作: useRef() // 1. Dom操作: useRef()let app doc…

一些指令工具

一、adb shell adb shell下一些常用命令行工具&#xff1a; pm&#xff1a;PackageManager&#xff0c;包管理器&#xff0c;用于管理應用程序的安裝、卸載、查詢和更多相關操作。 pm install …// pm uninstall …// pm list packages//設備上已安裝的應用程序 pm dump …//獲…

C運行時錯誤——error realloc(): invalid next size

在LeetCode做題時遇到一個運行時錯誤&#xff0c;將引起問題的原因記錄一下備忘&#xff1a; 我們在malloc或calloc等API分配內存時&#xff0c;libc庫除了分配給我們在參數中設定大小的內存&#xff08;可能會有內存對齊&#xff0c;實際分配的比參數設定的要多&#xff09;&…

填充柄功能

單元格右下角十字符號 順序式填充 輸入1,2&#xff0c;直接拉取即可實現順序1到10. 復制式填充 CtrlD或者拉取&#xff0c;選擇右下角復制單元格。 規律式填充 輸入星期一&#xff0c;星期二&#xff0c;下拉一直可以到星期日 自定義填充 選擇文件-》選項-》自定義序列 輸…

【python辦公自動化】PysimpleGUI中的popup彈窗中的按鈕設置居中

PysimpleGUI中的popup彈窗中的按鈕設置居中 背景問題解決背景 默認的popup彈窗中的OK按鈕是在最下面偏左側一些,有時需要將按鈕放置居中 問題解決 首先找到pysimplegui源代碼文件中popup的部分 然后定位到19388行,源文件內容如下 關于popup彈窗OK按鈕的設置,將pad屬性…

STM32——SPI外設總線

一、SPI外設簡介 STM32內部集成了硬件SPI收發電路&#xff0c;可以由硬件自動執行時鐘生成、數據收發等功能&#xff0c;減輕CPU的負擔【硬件電路自動生成時序】 可配置8位/16位數據幀、高位先行/低位先行 時鐘頻率&#xff1a; fPCLK / (2, 4, 8, 16, 32, 64, 128, 256)【SP…

面試之快速學習STL- vector

1. vector底層實現機制刨析&#xff1a; 簡述&#xff1a;使用三個迭代器表示的&#xff1a; &#xfffc; 這也就解釋了&#xff0c;為什么 vector 容器在進行擴容后&#xff0c;與其相關的指針、引用以及迭代器可能會失效的原因。 insert 整體向后移 erase 整體向前移…

關于uniapp微信小程序scroll-view組件使用show-scrollbar隱藏不了滾動條

這里關于使用 scroll-view組件 時候有滾動條 想要隱藏滾動條但是使用show-scrollbar沒有效果 這時候又使用類名隱藏滾動條 使用id隱藏滾動條都不行 解決方法&#xff1a;在使用 scroll-view組件 的頁面或者app 頁面加上以下代碼就可以了 ::-webkit-scrollbar {displa…

53.Linux day03 文件查看命令,vi/vim常用命令

今天進行了新的學習。 目錄 1.cat a.查看單個文件的內容&#xff1a; b.查看多個文件的內容&#xff1a; c.將多個文件的內容連接并輸出到一個新文件&#xff1a; d.顯示帶有行號的文件內容&#xff1a; 2.more 3.less 4.head 5.tail 6.命令模式 7.插入模式 8.圖…

BBS項目day04 文章詳情頁、點贊點菜、評論功能

一、路由 from django.contrib import admin from django.urls import path, re_path from app01 import views from django.views.static import serve from django.conf import settingsurlpatterns [path(admin/, admin.site.urls),# 注冊path(register/, views.register)…