步入React正殿 - State进阶

这篇具有很好参考价值的文章主要介绍了步入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进阶,React相关,react.js,前端,前端框架

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

步入React正殿 - State进阶,React相关,react.js,前端,前端框架

 单一数据源

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进阶,React相关,react.js,前端,前端框架

 @/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) => {
    // 使用不可变数据, 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-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;

状态提升

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

步入React正殿 - State进阶,React相关,react.js,前端,前端框架

 @/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) => {
    // 使用不可变数据, 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} />
        <ListPage
          data={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中显示的是商品种类数量,改造成商品的总数目文章来源地址https://www.toymoban.com/news/detail-650350.html

到了这里,关于步入React正殿 - State进阶的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 简介:在这篇教程中,我们将使用React.js框架创建一个简单的聊天机器人的前端界面,并利用Dialogflo

    作者:禅与计算机程序设计艺术 介绍及动机 聊天机器人(Chatbot)一直是互联网领域中的热门话题。而很多聊天机器人的功能都依赖于人工智能(AI)技术。越来越多的企业希望拥有自己的聊天机器人系统,从而提升自己的竞争力。为此,业界也出现了很多基于开源技术或云

    2024年02月06日
    浏览(57)
  • 【前端知识】React 基础巩固(二十三)——React 性能优化 SCU相关

    React 的渲染流程 JSX - 虚拟 DOM - 真实 DOM React 的更新流程 props/state 改变 - render函数重新执行 - 产生新的DOM树 - 新旧DOM树进行diff - 计算出差异进行更新 - 更新到真实的DOM React 在 props 或 state 发生改变时,会调用 React 的 render 方法,会创建一颗不同的树 React 需要基于这两颗不同的

    2024年02月15日
    浏览(71)
  • 前端框架学习-React(一)

    React 应用程序是由 组件 组成的。 react 程序是用的jsx语法,使用这种语法的代码需要由babel进行解析,解析成js代码。 jsx语法: 只能返回一个根元素 所有的标签都必须闭合(自闭和或使用一对标签的方式闭合) 使用驼峰式命名法给大部分属性命名如:className 大写字母开头的

    2024年02月12日
    浏览(40)
  • 前端框架 Nextjs React 部署

    目录 一、node环境部署 二、静态导出 补充:路由问题 Nextjs打包还是非常方便的,就是网上资料不太全,导致踩了一些坑,下面是我亲自实践的两种打包方式。 一、node环境部署 这种方式最简单,也比较不容易出错,但部署时服务器需安装有node环境,速度没话说,杠杠的! 构

    2024年02月12日
    浏览(42)
  • 丁鹿学堂:前端学习进阶指南之react入门(react在html中使用数据绑定和修改)

    在html中使用react 今天跟大家分享react的基础语法。 我们采用最简单的方法,就是在html中引入react 因为一上来就使用脚手架的话,很多配置大家不一定清楚。 而在html中使用react的话,可以直接去学习react最基本的语法。 这是零基础学习react的最佳实践。 引入react的依赖 react也

    2024年02月14日
    浏览(62)
  • Vue 和 React 前端框架的比较

    本文研究了流行的前端框架 Vue 和 React 之间的区别。通过对它们的学习曲线、视图层处理方式、组件化开发、响应式数据处理方式和生态系统及社区支持进行比较分析,得出了它们在不同方面的优劣和特点。该研究对于开发者在选择合适的前端框架时提供参考。 Vue 是一款由

    2024年02月13日
    浏览(63)
  • React与Vue:前端框架的比较

    在前端开发领域,React和Vue是两个备受瞩目的框架。它们都提供了构建用户界面的强大工具,但它们在实现方式、性能和设计理念上存在一些关键差异。本文将深入探讨这两个框架之间的主要区别。 首先,让我们从数据流的角度来看。在Vue中,数据流是双向的,这意味着组件

    2024年01月20日
    浏览(45)
  • 前端(七)——React框架的定位与应用场景解析

    😊博主:小猫娃来啦 😊文章核心: React框架的定位与应用场景解析 什么是react? React 是一个由 Facebook 开发的开源 JavaScript库,用于构建用户界面。 于2013年首次发布,并迅速成为前端开发中最受欢迎的框架之一。 在 React 诞生之前,前端开发面临着许多挑战,包括复杂的D

    2024年02月17日
    浏览(41)
  • JavaScript 框架比较:Angular、React、Vue.js

    在 Web 开发领域,JavaScript 提供大量技术栈可供选择。其中最典型的三套组合,分别是 MERN、MEAN 和 MEVN。这些首字母相同的选项各自代表不同的技术加工具组合。为了在这些技术栈中做出明智选择,让我们先从核心组件聊起,再对各自前端框架(React、Angular 和 Vue)进行简化比

    2024年01月20日
    浏览(56)
  • React与Vue性能对比:两大前端框架的性能

    React和Vue是当今最流行的两个前端框架,它们在性能方面都有着出色的表现。 React的加载速度: 初次加载:由于React使用了虚拟DOM(Virtual DOM)技术,它可以通过比较虚拟DOM树与实际DOM树的差异来进行高效的重绘。这使得React在初次加载时相对较快,因为它只会更新需要修改的

    2024年02月03日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包