• React学习5(React class 组件)


    类组件-无状态组件和有状态组件
    • 1.无状态组件

      • 组件本身不定义状态,没有组件生命周期,只负责 UI 渲染。
      • React16.8之前的函数组件都是无状态组件,Hooks 出现后函数组件也可以有状态。
    • 2.有状态组件

      • 组件本身有独立数据,拥有组件生命周期,存在交互行为。
      • class 组件可以定义组件自己的状态,拥有组件生命周期,它是有状态组件。
      1. 它们的区别
        无状态组件由于没有维护状态只做渲染,性能较好。有状态组件提供数据和生命周期,能力更强。
    • 4.如何去选择

      • React16.8之前,组件不需要维护数据只渲染就使用函数组件,有数据和交互使用类组件
      • React16.8之后,Hooks出现给函数提供状态,建议使用函数组件即可
    Rreact State(状态)

    React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。
    React 中,class组件有自己的state来维护组件内部的数据, 只需更新class组件的 state,然后就会根据新的 state 重新渲染用户界面(不要操作 DOM)。state是私有的,完全受控于当前组件.

    定义state属性定义组件状态,属于组件自己的数据,它的值是个对象
    使用state的时候通过this去访问即可,例如:this.state.xxx
    数据发生变化,驱动视图更新。组件初始在构造方法内可以给state赋值,然后在其他地方只能通过this.setState()来修改state的数据,修改数据之后会重新执行render方法进行刷新渲染视图

    以下实例创建一个名称扩展为 React.Component 的 ES6 类,在 render() 方法中使用 this.state 来修改当前的时间。
    添加一个类构造函数来初始化状态 this.state,类组件应始终使用 props 调用基础构造函数。

    import React, {Component} from 'react';
    
    class StateDemo extends Component {
        constructor() {
            super();
            this.state = {
                name: 'react',
                now: new Date()
            };
        }
        render() {
            return (
                <div>
                    <h1>hello {this.state.name}</h1>
                    <div>当前时间是: {this.state.now.toLocaleString()}</div>
                    <button onClick={()=>{this.setState({now: new Date()})}} >刷新时间</button>
                </div>
            );
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    React Props

    state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。这就是为什么有些容器组件需要定义 state 来更新和修改数据。 而子组件只能通过 props 来传递数据。

    Props的只读性

    组件无论是使用函数声明还是通过 class 声明,都绝不能修改自身的 props。

    React 非常灵活,但它也有一个严格的规则:
    所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。

    默认 Props

    可以通过组件类的 defaultProps 属性为 props 设置默认值,实例如下:

    class Welcome extends React.Component {
      render() {
        return (
          <h1>Hello, {this.props.name}</h1>
        );
      }
    }
    Welcome.defaultProps = {
      name: 'react'
    };
     
    const element = <Welcome/>;
     
    ReactDOM.render(
      element,
      document.getElementById('root')
    );
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    Props 验证

    React.PropTypes 在 React v15.5 版本后已经移到了 prop-types 库,使用验证需要引入对应的cdn库

    <script src="https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js">script>
    
    • 1

    rops 验证使用 propTypes,它可以保证我们的应用组件被正确使用,React.PropTypes 提供很多验证器 (validator) 来验证传入数据是否有效。当向 props 传入无效数据时,JavaScript 控制台会抛出警告。

    class Welcome extends React.Component {
      render() {
        return (
          <h1>Hello, {this.props.name}</h1>
        );
      }
    }
    Welcome.propTypes = {
      name: PropTypes.string
    };
     
    const element = <Welcome name={123} />;
     
    ReactDOM.render(
      element,
      document.getElementById('root')
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    类组件-绑定事件
    掌握类组件中绑定事件的方式,和获取事件对象的方式。

    大致步骤:

    在类中声明事件处理函数,在标签上使用on+事件名称={处理函数}的方式绑定事件,事件名称需要遵循大驼峰规则。
    处理函数默认的参数就是事件对象,可以使用事件对象处理默认行为和事件冒泡。

    class组件的创建

    react的组件可以定义为class或函数的形式,class组件目前提供了更多的功能. 如需定义class组件,需要继承React.Component

    class Welcome extends React.Component {
      render() {
        return <h1>Hello, {this.props.name}</h1>;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    React.Component 的子类中有个必须定义的 render() 函数。
    强烈建议不要创建自己的组件基类。 在 React 组件中,代码重用的主要方式是组合而不是继承.
    React 并不会强制你使用 ES6 的 class 语法。如果你倾向于不使用它,你可以使用 create-react-class 模块或类似的自定义抽象来代替。请查阅不使用 ES6 了解更多

    组件的生命周期

    每个组件都包含“生命周期方法”,你可以重写这些方法,以便于在运行过程中特定的阶段执行这些方法。在下述列表中,常用的生命周期方法会被加粗。(生命周期图谱)

    在这里插入图片描述

    函数的生命周期 主要分为三个阶段 :挂载(已插入真实 DOM)、更新(正在被重新渲染)、卸载(已移出真实DOM) .

    class LifeDemo extends Component {
        constructor() {
            super();
            console.log('======执行了构造方法');
            // 构造方法中直接给state赋初始值 不能执行setState
            this.state = {name:'react'}
        }
    
        componentWillMount() {
            console.log('=======组件将要挂载,执行了componentWillMount')
        }
    
        componentDidMount() {
            console.log('======组件挂载到dom节点完成,执行了componentDidMount方法');
        }
    
        shouldComponentUpdate(nextProps, nextState, nextContext) {
            console.log('=====执行了shouldComponentUpdate 组件在受到props或者state更新要判断是否执行render方法刷新视图, 返回false则不执行render');
            // 当state中name变为vue时,视图不更新
            if (nextState.name === 'vue') {
                return false;
            }
            return true;
        }
    
        componentDidUpdate(prevProps, prevState, snapshot) {
            console.log('=====组件更新完成之后,执行了componentDidUpdate')
        }
    
        componentWillUnmount() {
            // 一般用于处理消除定时器、订阅
            console.log('======组件将要移除时,执行componentWillUnmount')
        }
    
    
        render() {
            console.log('======执行了render方法');
            return (
                <div>
                    组件生命周期Demo
                    <div>hello {this.state.name}</div>
                    <input type="text" value={this.state.name}
                           onChange={(e)=>{
                               console.log(e.target.value);
                               console.log(this);
                               this.setState({name: e.target.value})
                           }} />
                </div>
            );
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    挂载

    当组件实例被创建并插入DOM 中时,生命周期调用顺序如下:

    • constructor()
    • static getDerivedStateFromProps()
    • render()
    • componentDidMount()

    下述生命周期方法即将过时,在新代码中应该避免使用它们:
    UNSAFE_componentWillMount()

    更新

    当组件的 props 或 state 发生变化时会触发更新。组件更新的生命周期调用顺序如下:

    • static getDerivedStateFromProps()
    • shouldComponentUpdate()
    • render()
    • getSnapshotBeforeUpdate()
    • componentDidUpdate()

    下述方法即将过时,在新代码中应该避免使用它们:
    UNSAFE_componentWillUpdate()
    UNSAFE_componentWillReceiveProps()

    更新

    当组件从 DOM 中移除时会调用如下方法:

    • componentWillUnmount()
    错误处理

    当渲染过程,生命周期,或子组件的构造函数中抛出错误时,会调用如下方法:

    • static getDerivedStateFromError()
    • componentDidCatch()
    其他 APIs
    • setState()
    • forceUpdate()
    class 属性
    • defaultProps
    • displayName
    实例属性
    • props
    • state
    常用生命周期方法
    render():
    render()
    
    • 1

    render() 方法是 class 组件中唯一必须实现的方法。

    当 render 被调用时,它会检查 this.props 和 this.state 的变化并返回以下类型之一:

    • React 元素。通常通过 JSX 创建。例如,
      会被 React 渲染为 DOM 节点, 会被 React 渲染为自定义组件,无论是
      还是 均为 React 元素。
    • 数组或 fragments。 使得 render 方法可以返回多个元素。欲了解更多详细信息,请参阅 fragments 文档。
    • Portals。可以渲染子节点到不同的 DOM 子树中。(Portals是一个可以插入指定dom节点下的element元素)欲了解更多详细信息,请参阅有关 portals 的文档
    • 字符串或数值类型。它们在 DOM 中会被渲染为文本节点
    • 布尔类型或 null。什么都不渲染。(主要用于支持返回 test && 的模式,其中 test 为布尔类型。)

    render() 函数应该为纯函数,这意味着在不修改组件 state 的情况下,每次调用时都返回相同的结果,并且它不会直接与浏览器交互。
    如需与浏览器进行交互,请在 componentDidMount() 或其他生命周期方法中执行你的操作。保持 render() 为纯函数,可以使组件更容易思考。

    在组件更新阶段,执行render之前会调用shouldComponentUpdate()方法, 如果 shouldComponentUpdate() 返回 false,则不会调用 render()。

    constructor()
    constructor(props)
    
    • 1

    如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数。
    在 React 组件挂载之前,会调用它的构造函数。在为 React.Component 子类实现构造函数时,应在其他语句之前前调用 super(props)。否则,this.props 在构造函数中可能会出现未定义的 bug。

    通常,在 React 中,构造函数仅用于以下两种情况:

    • 通过给 this.state 赋值对象来初始化内部 state。
    • 为事件处理函数绑定实例

    在 constructor() 函数中**不要调用 setState() **方法。如果组件需要使用内部 state,请直接在构造函数中为 this.state 赋值初始 state: 只能在构造函数中直接为 this.state 赋值。如需在其他方法中赋值,你应使用 this.setState() 替代。

    constructor(props) {
      super(props);
      // 不要在这里调用 this.setState()
      this.state = { counter: 0 };
      this.handleClick = this.handleClick.bind(this);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    componentDidMount()()
    componentDidMount()
    
    • 1

    componentDidMount() 会在组件挂载后(插入 DOM 树中)立即调用。依赖于 DOM 节点的初始化应该放在这里。如需通过网络请求获取数据,此处是实例化请求的好地方。

    这个方法是比较适合添加订阅的地方。如果添加了订阅,请不要忘记在 componentWillUnmount() 里取消订阅

    可以在 componentDidMount() 里直接调用 setState()。它将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。如此保证了即使在 render() 两次调用的情况下,用户也不会看到中间状态。请谨慎使用该模式,因为它会导致性能问题。通常,你应该在 constructor() 中初始化 state。如果渲染依赖于 DOM 节点的大小或位置,比如实现 modals 和 tooltips 等情况下,你可以使用此方式处理

    componentDidUpdate()
    componentDidUpdate(prevProps, prevState, snapshot)
    
    • 1

    componentDidUpdate() 会在更新后会被立即调用。首次渲染不会执行此方法。

    当组件更新后,可以在此处对 DOM 进行操作。如果你对更新前后的 props 进行了比较,也可以选择在此处进行网络请求。(例如,当 props 未发生变化时,则不会执行网络请求)。

    componentDidUpdate(prevProps) {
      // 典型用法(不要忘记比较 props):
      if (this.props.userID !== prevProps.userID) {
        this.fetchData(this.props.userID);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    你也可以在 componentDidUpdate() 中直接调用 setState(),但请注意它必须被包裹在一个条件语句里,正如上述的例子那样进行处理,否则会导致死循环。它还会导致额外的重新渲染,虽然用户不可见,但会影响组件性能。不要将 props “镜像”给 state,请考虑直接使用 props。
    如果组件实现了 getSnapshotBeforeUpdate()生命周期(不常用),则它的返回值将作为 componentDidUpdate() 的第三个参数 “snapshot” 参数传递。否则此参数将为 undefined。

    如果 shouldComponentUpdate() 返回值为 false,则不会调用 componentDidUpdate()

  • 相关阅读:
    Python利用selenium框架抓取京东的地址数据
    5分钟带你了解什么是敏捷测试?难点显而易见!
    ElasticSearch综合练习题,ES为8版本,使用Kibana运行语句
    08 MyBatis 注解开发
    C++ 中迭代器的使用
    前后端分离前端部署方案是什么?
    CSS transition和animation的用法和区别
    Mybatis复杂查询及动态SQL
    上午卷-5.系统开发与运营-软件设计师
    Attention Transformer
  • 原文地址:https://blog.csdn.net/qq_40600414/article/details/126413898