目錄
擴(kuò)展學(xué)習(xí)資料
State進(jìn)階知識(shí)點(diǎn)
狀態(tài)更新擴(kuò)展
shouldComponentUpdate
PureComponent
為何使用不變數(shù)據(jù)【保證數(shù)據(jù)引用不會(huì)出錯(cuò)】
?單一數(shù)據(jù)源
?@/src/App.js
@/src/components/listItem.jsx
狀態(tài)提升
?@/src/components/navbar.jsx
@/src/components/listPage.jsx
@src/App.js
有狀態(tài)組件&無狀態(tài)組件
Stateful【有狀態(tài)】和Stateless【無狀態(tài)】的區(qū)別
Stateful
Stateless
小結(jié)
練習(xí)
擴(kuò)展學(xué)習(xí)資料
預(yù)習(xí)資料名稱? |
鏈接 |
備注 |
不可變數(shù)據(jù) |
https://github.com/immutable-js/immutable-js |
無 |
JS內(nèi)存管理 |
內(nèi)存管理 - JavaScript | MDN |
無 |
狀態(tài)提升 |
mangojuice.top?-?該網(wǎng)站正在出售!?-?mangojuice 資源和信息。 |
擴(kuò)展閱讀 |
context管理狀態(tài) |
http://react.html.cn/docs/context.html ? 聊一聊我對(duì) React Context 的理解以及應(yīng)用 - 掘金 |
擴(kuò)展閱讀 |
State進(jìn)階知識(shí)點(diǎn)
- 通過條件判斷優(yōu)化渲染
- 使用不可變數(shù)據(jù)
- 狀態(tài)提升
- 使用無狀態(tài)組件
狀態(tài)更新擴(kuò)展
阻止不必要的render方法執(zhí)行
shouldComponentUpdate
// render渲染執(zhí)行前調(diào)用的函數(shù),返回false,可以有效的阻止不必要的render方法執(zhí)行
? 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 {}
為何使用不變數(shù)據(jù)【保證數(shù)據(jù)引用不會(huì)出錯(cuò)】
// ...
handleDelete = (id) => {
? ? // 使用不可變數(shù)據(jù), filter返回一個(gè)新數(shù)組
? ? const listData = this.state.listData.filter((item) => item.id !== id);
? ? this.setState({
? ? ? listData,
? ? });
? };
? handleAmount = () => {
? ? // 如不使用新的數(shù)組【沒有使用不可變數(shù)據(jù)】, state變化,不會(huì)重新渲染UI
? ? //
? ? const _list = this.state.listData.concat([]);
? ? /*
? ? ? pop() 方法用于刪除數(shù)組的最后一個(gè)元素并返回刪除的元素。
? ? ? 注意:此方法改變數(shù)組的長(zhǎng)度!
? ? ? 提示: 移除數(shù)組第一個(gè)元素,請(qǐng)使用 shift() 方法。
? ? */
? ? _list.pop();
? ? this.setState({
? ? ? listData: _list,
? ? });
? };
// ...
如下圖,如果沒有創(chuàng)建新的引用,在PureComponent中,不會(huì)調(diào)用render
?如下圖,使用不可變數(shù)據(jù),可以避免引用帶來的副作用,使得整個(gè)程序數(shù)據(jù)變的易于管理
?單一數(shù)據(jù)源
handleReset = () => {
? ? // 使用map方法創(chuàng)建一個(gè)新的數(shù)組
? ? const _list = this.state.listData.map((item) => {
? ? ? // ... 解構(gòu)符
? ? ? const _item = { ...item };
? ? ? _item.value = 0;
? ? ? return _item;
? ? });
? ? this.setState({
? ? ? listData: _list,
? ? });
? ? // 此時(shí)props數(shù)據(jù)變化,子組件state.count沒變化
? ? // 原因出在沒有使用單一數(shù)據(jù)源
? };
?@/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 (
? ? ? ? <ListItem
? ? ? ? ? key={item.id}
? ? ? ? ? data={item}
? ? ? ? ? onDelete={this.handleDelete}
? ? ? ? ? onDecrease={this.handleDecrease}
? ? ? ? ? onAdd={this.handleAdd}
? ? ? ? />
? ? ? );
? ? });
? }
? handleDelete = (id) => {
? ? // 使用不可變數(shù)據(jù), filter返回一個(gè)新數(shù)組
? ? const listData = this.state.listData.filter((item) => item.id !== id);
? ? this.setState({
? ? ? listData,
? ? });
? };
? handleDecrease = (id) => {
? ? // 使用不可變數(shù)據(jù), filter返回一個(gè)新數(shù)組
? ? 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) => {
? ? // 使用不可變數(shù)據(jù), filter返回一個(gè)新數(shù)組
? ? 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 = () => {
? ? // 如不使用新的數(shù)組【沒有使用不可變數(shù)據(jù)】, state變化,不會(huì)重新渲染UI
? ? //
? ? const _list = this.state.listData.concat([]);
? ? /*
? ? ? pop() 方法用于刪除數(shù)組的最后一個(gè)元素并返回刪除的元素。
? ? ? 注意:此方法改變數(shù)組的長(zhǎng)度!
? ? ? 提示: 移除數(shù)組第一個(gè)元素,請(qǐng)使用 shift() 方法。
? ? */
? ? _list.pop();
? ? this.setState({
? ? ? listData: _list,
? ? });
? };
? handleReset = () => {
? ? // 使用map方法創(chuàng)建一個(gè)新的數(shù)組
? ? const _list = this.state.listData.map((item) => {
? ? ? // ... 結(jié)構(gòu)符
? ? ? const _item = { ...item };
? ? ? _item.value = 0;
? ? ? return _item;
? ? });
? ? this.setState({
? ? ? listData: _list,
? ? });
? ? // 此時(shí)props數(shù)據(jù)變化,子組件state.count沒變化
? ? // 原因出在沒有使用單一數(shù)據(jù)源
? };
? render() {
? ? return (
? ? ? <div className='container'>
? ? ? ? <button onClick={this.handleAmount} className='btn btn-primary'>
? ? ? ? ? 減去最后一個(gè)
? ? ? ? </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 {
? // 類的構(gòu)造函數(shù)
? // eslint-disable-next-line no-useless-constructor
? constructor(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>
? ? ? ? <div
? ? ? ? ? className={`col-2 themed-grid-col${
? ? ? ? ? ? this.props.data.value ? '' : '-s'
? ? ? ? ? }`}>
? ? ? ? ? <button
? ? ? ? ? ? onClick={() => {
? ? ? ? ? ? ? this.props.onDecrease(this.props.data.id);
? ? ? ? ? ? }}
? ? ? ? ? ? type='button'
? ? ? ? ? ? className='btn btn-primary'>
? ? ? ? ? ? -
? ? ? ? ? </button>
? ? ? ? ? <span className={cls('digital')}>{this.props.data.value}</span>
? ? ? ? ? <button
? ? ? ? ? ? onClick={() => {
? ? ? ? ? ? ? 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'>
? ? ? ? ? <button
? ? ? ? ? ? onClick={() => {
? ? ? ? ? ? ? this.props.onDelete(this.props.data.id);
? ? ? ? ? ? }}
? ? ? ? ? ? type='button'
? ? ? ? ? ? className='btn btn-danger btn-sm'>
? ? ? ? ? ? 刪除
? ? ? ? ? </button>
? ? ? ? </div>
? ? ? </div>
? ? );
? }
}
export default ListItem;
狀態(tài)提升
處理組件和子組件數(shù)據(jù)傳遞,自頂向下單向流動(dòng)
?@/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>
? ? ? ? ? ? <button
? ? ? ? ? ? ? onClick={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 (
? ? ? ? <ListItem
? ? ? ? ? key={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) => {
? ? // 使用不可變數(shù)據(jù), filter返回一個(gè)新數(shù)組
? ? const listData = this.state.listData.filter((item) => item.id !== id);
? ? this.setState({
? ? ? listData,
? ? });
? };
? handleDecrease = (id) => {
? ? // 使用不可變數(shù)據(jù), filter返回一個(gè)新數(shù)組
? ? 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) => {
? ? // 使用不可變數(shù)據(jù), filter返回一個(gè)新數(shù)組
? ? 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 = () => {
? ? // 如不使用新的數(shù)組【沒有使用不可變數(shù)據(jù)】, state變化,不會(huì)重新渲染UI
? ? //
? ? const _list = this.state.listData.concat([]);
? ? /*
? ? ? pop() 方法用于刪除數(shù)組的最后一個(gè)元素并返回刪除的元素。
? ? ? 注意:此方法改變數(shù)組的長(zhǎng)度!
? ? ? 提示: 移除數(shù)組第一個(gè)元素,請(qǐng)使用 shift() 方法。
? ? */
? ? _list.pop();
? ? this.setState({
? ? ? listData: _list,
? ? });
? };
? handleReset = () => {
? ? // 使用map方法創(chuàng)建一個(gè)新的數(shù)組
? ? const _list = this.state.listData.map((item) => {
? ? ? // ... 結(jié)構(gòu)符
? ? ? const _item = { ...item };
? ? ? _item.value = 0;
? ? ? return _item;
? ? });
? ? this.setState({
? ? ? listData: _list,
? ? });
? ? // 此時(shí)props數(shù)據(jù)變化,子組件state.count沒變化
? ? // 原因出在沒有使用單一數(shù)據(jù)源
? };
? render() {
? ? return (
? ? ? <>
? ? ? ? <Nav itemNum={this.state.listData.length} onReset={this.handleReset} />
? ? ? ? <ListPage
? ? ? ? ? data={this.state.listData}
? ? ? ? ? handleAdd={this.handleAdd}
? ? ? ? ? handleAmount={this.handleAmount}
? ? ? ? ? handleDecrease={this.handleDecrease}
? ? ? ? ? handleDelete={this.handleDelete}
? ? ? ? ? handleReset={this.handleReset}
? ? ? ? />
? ? ? </>
? ? );
? }
}
export default App;
有狀態(tài)組件&無狀態(tài)組件
Stateful【有狀態(tài)】和Stateless【無狀態(tài)】的區(qū)別
Stateful
- 類組件
- 有狀態(tài)組件
- 容器組件
Stateless
- 函數(shù)組件
- 無狀態(tài)組件
- 展示組件
盡可能通過狀態(tài)提升原則,將需要的狀態(tài)提取到父組件中,而其他的組件使用無狀態(tài)組件編寫【父組件有狀態(tài),子組件無狀態(tài)】
無狀態(tài)組件簡(jiǎn)單好維護(hù),單一從上而下的數(shù)據(jù)流
小結(jié)
- 優(yōu)化渲染
- 使用不可變數(shù)據(jù)
- 單一數(shù)據(jù)源以及狀態(tài)提升
- 無狀態(tài)組件寫法
練習(xí)
【題目1】?用單一數(shù)據(jù)源原則和狀態(tài)提升原則改造購物車工程文章來源:http://www.zghlxwxcb.cn/news/detail-650350.html
【題目2】 目前Header中顯示的是商品種類數(shù)量,改造成商品的總數(shù)目文章來源地址http://www.zghlxwxcb.cn/news/detail-650350.html
到了這里,關(guān)于步入React正殿 - State進(jìn)階的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!