步入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

步入React正殿 - State进阶_第1张图片

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

步入React正殿 - State进阶_第2张图片

 单一数据源

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

步入React正殿 - State进阶_第3张图片

 @/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 (
        
      );
    });
  }
  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 (
      
                        {this.state.listData.length === 0 && (          
购物车是空的
        )}         {this.renderList()}      
    );   } } 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-constructor
  constructor(props) {
    super(props);
  } 
  render() {
    console.log('item is rendering');
    return (
      
       
                      {this.props.data.name}                  
       
          ¥{this.props.data.price}        
       
                    {this.props.data.value}                  
       
          ¥ {this.props.data.price * this.props.data.value}        
       
                 
     
    );   } } export default ListItem;

状态提升

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

步入React正殿 - State进阶_第4张图片

 @/src/components/navbar.jsx

import React, { PureComponent } from 'react';
class Nav extends PureComponent {
  render() {
    return (
      
    );
  }
}
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 (
        
      );
    });
  }
  render() {
    return (
      
        {this.props.data.length === 0 && (          
购物车是空的
        )}         {this.renderList()}      
    );   } } 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 (
      <>
        

有状态组件&无状态组件

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

Stateful

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

Stateless

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

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

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

小结

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

练习

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

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

你可能感兴趣的:(React相关,react.js,前端,前端框架)