React - 类组件

前言

  • 先简单记录下,后续慢慢在慢慢补充吧;

React创建组件的两种方式

  • Class
    • 已被官方废弃(源码中依然保留),但是需要了解学习,为函数式组件做铺垫;
    • 可以直接反映出React运行时的整个生命周期;
    • 很多的项目中还是有用Class组件的;
  • Function(纯函数):
    • 后续都会使用这种方式;

类组件样板代码

TS

ts 复制代码
import React from 'react';

interface PropsType {};

interface StateType {};

class ClassCom extends React.Component<PropsType, StateType> {
  /** 会在组件挂载前执行 */
  // class组件的执行过程,首先肯定是执行实例化,也就是执行 constructor;
  constructor(props: PropsType) {
    super(props);
    // 在这里定义状态
    this.state = {};
  }
  
  handleClick() {
    console.log('嘻嘻哈哈');
  }

  // 渲染组件:【constructor之后、挂载之前执行】
  render() {
    return (
      <div className="class-com">
        ClassComponent
        <button onClick={() => this.handleClick()}>click</button>
      </div>
    )
  }
}

export default ClassCom;

JS

js 复制代码
import { Component } from 'react';

export default class ClassCom extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }
  render() {
    return (
      <div>
        <h1>我是ClassCom组件</h1>
      </div>
    );
  }
}
JS指定props类型
  • 对于TS,我们可以指定props中每个属性的类型,减少后期开发的类型错误;
  • 而对于JS,我们可以prop-types这个第三方模块指定类型;
  • 如果传递的属性类型不匹配,控制台就会有警告;
js 复制代码
import { Component } from 'react';
import PropTypes from 'prop-types';

export default class Son extends Component {

  constructor(props) {
    super(props);
    this.state = {};
  }

  render() {
    return (
      <div>
        <h1>我是子组件</h1>
      </div>
    );
  }
};

// 给组件添加 propTypes【自定义】 属性
Son.propTypes = {
  // 指定 name 为 字符串,并且 必传
  name: PropTypes.string.isRequired,
  age: PropTypes.number.isRequired,
  // 指定 like 为 数组,非必传
  like: PropTypes.array
};
ts 复制代码
constructor(props) {
 super(props);
}
  • 类函数 constructor 基础代码解释:
  • 这段代码是JS类构造函数的一部分,功能如下:
    • 调用父类的构造函数 super(props) ,将传入的 props 参数传递给父类构造函数进行初始化
    • 确保子类能够正确继承和初始化父类的状态和属性;

一、状态的定义和修改

  • 目标位置:

    • constructor()
  • 定义状态

    • 这是类组件 ,定义state的时候要在this.state中去定义;
  • 访问状态

    • 访问的时候,也要基于this.state去访问(可以进行解构);
  • 修改状态

    • 修改state的时候,要使用this.setState()进行修改;
  • 示例:

    ts 复制代码
    import React, { ReactNode } from 'react';
    
    interface PropsType {};
    
    interface StateType {
      name: string;
    };
    
    class ClassCom extends React.Component<PropsType, StateType> {
      constructor(props: PropsType) {
        super(props);
        // 定义状态 - this.state
        this.state = {
          name: 'React 类组件 ClassComponent'
        };
      }
    
      handleClick = () => {
        // 修改state - this.setState
        this.setState({
          name: new Date().getTime(),
        });
      };
    
      render() {
        // 访问state - 解构
        const { name } = this.state;
        return (
          <>
            <div className="class-com">{name}div>
            <button onClick={this.handleClick}>edit name</button>
          </>
        )
      }
    }

二、绑定事件

  • 在 React 类组件中,this 关键字在类方法中默认是 undefined,这是因为 JavaScript 中的类方法不会自动绑定 this 到类的实例。为了解决这个问题,可以使用以下几种方法之一:
    1. 在构造函数中绑定 this
      • 在类的构造函数中使用 .bind(this) 来绑定 this 到类的实例。
    2. 使用箭头函数
      • 在定义方法时使用箭头函数,箭头函数会自动绑定 this 到定义时的上下文。
    3. 在 JSX 中绑定 this
      • 在 JSX 中使用箭头函数来调用方法,这样可以确保 this 正确绑定。
js 复制代码
import { Component } from 'react'
import PropTypes from 'prop-types';

export default class Son extends Component {
  constructor(props) {
    super(props);
    this.state = {
      newName: '嘻哈少将',
      newAge: 20,
      newLike: ['吃烧烤', '喝啤酒']
    };
    // 方式一 - 在构造函数中绑定this
    this.editNewLike = this.editNewLike.bind(this);
  }
  
  // 方式二 - 箭头函数
  editNewAge = () => {
    this.setState({ newAge: 30 });
  };

  // 方式三 - 在JSX中绑定this
  editNewName() {
    this.setState({ newName: '哈哈哈' });
  };

  editNewLike() {
    this.setState({ newLike: ['唱', '跳', 'rap', '篮球'] });
  };

  render() {
    const { name, age, like, } = this.props;
    const { newName, newAge, newLike } = this.state;
    return (
      <div>
        <h1>我是子组件</h1>
        <div>old:{name} ===》 new:{newName}</div>
        <div>old:{age} ===》 new:{newAge}</div>
        {like && <div>old:{like.join('、')} ===》 new:{newLike.join('、')}</div>}
        <button onClick={() => this.editNewName()}>edit new-name</button> <br />
        <button onClick={this.editNewAge}>edit new-age</button> <br />
        <button onClick={this.editNewLike}>edit new-like</button> <br />
      </div>
    );
  }
};

// 给自组件添加 propTypes 属性
Son.propTypes = {
  name: PropTypes.string.isRequired,
  age: PropTypes.number.isRequired,
  like: PropTypes.array,
};

三、生命周期

生命周期示例图:

2.1 初始化(挂载时、创建时)

  • React Class组件的执行过程,肯定先是执行类的实例化,也就是constructor
    • 不管哪个生命周期,肯定都是在constructor之后执行的;
  • getDerivedStateFromProps,在组件挂载之前执行(render执行之前调用),返回值会赋给state
  • 然后执行render函数,去渲染页面(挂载前);
  • 渲染完成之后执行componentDidMount(挂载后);
    • 注意
      • 该钩子函数不接受任何参数,也不应该返回任何值;

2.2 更新时

  • 当我们的状态更新时;
  • 首先会触发getDerivedStateFromProps(props, state)生命周期钩子函数;
    • 注意
      • 该方法是静态方法 ,定义的时候,需要在函数名前面添加static
    • 执行时机
      • React会在 初始挂载后续更新时 调用render之前调用它;
    • 参数
      • props:组件即将用来渲染的下一个props;
      • state:组件即将渲染的下一个state;
    • 返回值
      • 返回一个对象来更新state
        • 返回的指会对state中的对应值进行覆盖;
          • 相同属性覆盖;
          • 返回的对象中有和state相同的属性就覆盖;
          • 若没有相同的属性,就不会触发覆盖;
        • 因为该钩子函数会在初始化挂载和更新时调用render之前调用,所以当对对应的state做出修改的时候,页面上的只是不会更新的,都被拦截掉了(覆盖了);
      • 或者返回null就不更新任何内容;
    • 注意
      • 该钩子函数的两个参数,若发生相同属性覆盖行为,就会发现,参数props和参数state与下次要渲染的props和state不相同;
      • 当我们触发修改的时候,其实props和state都已经修改成功了,但是被该钩子函数返回的相同属性覆盖了;
  • 接着会调用getSnapshotBeforeUpdate(prevProps, prevState)
    • 执行时机
      • render之后,页面真正更新之前;
      • react只要执行了setState,render就会执行,也就是执行这些钩子函数;
    • 作用
      • React会在React更新DOM之前直接调用它;
      • 在更新之前获取一些信息;
    • 参数
      • prevProps
        • 更新之前的Props;
        • prevProps将会与this.props进行比较来确定发生了什么变化;
      • prevState
        • 更新之前的State;
        • prevState将会与this.state进行比较来确定发生了什么变化;
      • 渲染之前的值;
    • 返回值
      • 应该返回想要的任何类型的快照值或者是null
    • 使用场景
      • 有个长列表,需要不断的往里面加入内容;
        • 更新之前,记住滚轮的位置,传递给componentDidUpdate,保持滚轮的位置(提升用户体验);
  • 最后执行componentDidUpdate(prevProps, prevState, snapshot?)
    • 执行时机
      • React会在组件更新了props和state 重新渲染后 立即调用它;
    • 参数
      • prevProps
        • 更新之前的props;
        • prevProps将会与this.props进行比较来确定发生了什么变化;
      • prevState
        • 更新之前的state;
        • prevState将会与this.state进行比较来确定发生了什么变化;
      • snapshot(非必传):
        • 如果你实现了getSnapshotBeforeUpdate,那么snapshot将包含从该方法返回的值。否则它就是undefined;
    • 返回值
      • 不应该返回任何值;
    • 使用场景
      • 可以在一次更新后使用它来操作DOM;
    • 注意
      • 如果你定义了shouldComponentUpdate并且返回值为false的话,那么componentDidUpdate将不会被调用;
      • 建议不要在该钩子函数中直接调用setState,会造成性能问题;

2.3 卸载时

  • 组件卸载时,会将状态进行重置;
  • componentWillUnmount()
  • 如果你定义了 componentWillUnmount 方法,React 会在你的组件 卸载 之前调用它。
  • 此方法常常用于取消数据获取或移除监听事件。
  • 该钩子函数没有任何参数也没有任何的返回值;
相关推荐
screct_demo23 分钟前
详细讲一下Vue的路由Vue Router的安装,配置,基础用法和详细用法以及实践中应用
前端·javascript·vue.js
林涧泣25 分钟前
【Uniapp-Vue3】使用ref定义响应式数据变量
前端·vue.js·uni-app
PieroPc35 分钟前
特制一个自己的UI库,只用CSS、图标、emoji图 日后慢用!!!
javascript·css·ui
HelloZheQ35 分钟前
CSS 变量:让你的样式更灵活、更易维护
前端·css·tensorflow
wh39332 小时前
深入理解 React 前端框架:构建高效用户界面的利器
react.js·ui·前端框架
♟彦♟2 小时前
web-前端小实验2
前端
G_qingxin2 小时前
前端排序算法
前端·算法·排序算法
He guolin2 小时前
[Vue]的快速上手
前端·javascript·vue.js
flying robot2 小时前
Rust的对web生态的影响
开发语言·前端·rust
艾斯特_2 小时前
window.open 被浏览器拦截解决方案
前端·javascript