• React学习(三)— React State和生命周期



    React将组件(component)看成一个状态机(State Machines),通过其内部自定义的状态(State)和生命周期(Lifecycle)实现并与用户交互,维持组件的不同状态。

    一、State

    在React当中,当你更新组件的state,然后新的state就会重新渲染到页面中。在这个时候不需要你操作任何DOM。这和vue中组件的data中的数据是相似的。

    1.1 类组件中的State

    DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Statetitle>
        <script src="https://cdn.staticfile.org/react/16.8.0/umd/react.development.js">script>
        <script src="https://cdn.staticfile.org/react-dom/16.8.0/umd/react-dom.development.js">script>
        
        <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js">script>
      head>
      <body>
        <div id="app">div>
        <script type="text/babel">
          class Clock extends React.Component {
            constructor(props) {
              super(props);
              this.state = { title: "React State", date: new Date() };
              this.handleClick = this.handleClick.bind(this);
            }
            handleClick() {
              this.setState({ date: new Date() });
            }
            render() {
              return (
                <div>
                  <p>{this.state.title}</p>
                  <p>现在是 {this.state.date.toLocaleTimeString()}.</p>
                  <button onClick={this.handleClick}>更新时间</button>
                </div>
              );
            }
          }
    
          ReactDOM.render(<Clock />, document.getElementById("app"));
        script>
      body>
    html>
    
    
    • 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

    在这里插入图片描述
    类组件需要在constructor中定义this.state对象,其对应的属性就是需要使用的state,例如上面代码中的title和date属性,在render函数中通过this.sate.XXX调用。

    注意,修改state需要调用this.setState方法,不可以直接对state进行赋值。

    这里的handleClick是按钮的点击事件,点击按钮后,调用setState方法重新为date赋值,此时页面会自动更新。

    1.2 函数组件中的State

    函数组件没有state => React v16.8.0推出Hooks API,其中的一个API叫做useState可以解决问题。

    DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Statetitle>
        <script src="https://cdn.staticfile.org/react/16.8.0/umd/react.development.js">script>
        <script src="https://cdn.staticfile.org/react-dom/16.8.0/umd/react-dom.development.js">script>
        
        <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js">script>
      head>
      <body>
        <div id="app">div>
        <script type="text/babel">
          const Clock = (props) => {
            const [n, setN] = React.useState(0);
            function addNum() {
              setN(n + 1);
            }
            return (
              <div>
                <p>现在的n是 {n} .</p>
                <button onClick={addNum}>n+1</button>
              </div>
            );
          };
    
          ReactDOM.render(<Clock />, document.getElementById("app"));
        script>
      body>
    html>
    
    
    • 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

    可以看到,在函数组件中使用state需要借助useState,并且useState会返回setXXX方法用于修改定义的state,相比于类组件,函数组件更加简洁,而且不用关注修改state时的this指向问题。

    二、React生命周期

    组件的生命周期可分成三个状态:

    • Mounting(挂载):已插入真实 DOM
    • Updating(更新):正在被重新渲染
    • Unmounting(卸载):已移出真实 DOM

    2.1 挂载

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

    1. constructor(): 在 React 组件挂载之前,会调用它的构造函数。
    2. getDerivedStateFromProps():在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。
    3. render(): render() 方法是 class组件中唯一必须实现的方法。
    4. componentDidMount(): 在组件挂载后(插入 DOM 树中)立即调用。

    render() 方法是 class 组件中唯一必须实现的方法,其他方法可以根据自己的需要来实现。

    2.2 更新

    每当组件的 state 或 props 发生变化时,组件就会更新。

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

    1. getDerivedStateFromProps(): 在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。根据shouldComponentUpdate() 的返回值,判断 React 组件的输出是否受当前 state 或 props更改的影响。
    2. shouldComponentUpdate():当 props 或 state 发生变化时,shouldComponentUpdate() 会在渲染执行之前被调用。
    3. render(): render() 方法是 class 组件中唯一必须实现的方法。
    4. getSnapshotBeforeUpdate(): 在最近一次渲染输出(提交到 DOM节点)之前调用。
    5. componentDidUpdate(): 在更新后会被立即调用。

    render() 方法是 class 组件中唯一必须实现的方法,其他方法可以根据自己的需要来实现。

    2.3 卸载

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

    1. componentWillUnmount(): 在组件卸载及销毁之前直接调用。
    DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Lifecycletitle>
        <script src="https://cdn.staticfile.org/react/16.8.0/umd/react.development.js">script>
        <script src="https://cdn.staticfile.org/react-dom/16.8.0/umd/react-dom.development.js">script>
        
        <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js">script>
      head>
      <body>
        <div id="app">div>
        <script type="text/babel">
          class Button extends React.Component {
            constructor(props) {
              super(props);
              this.state = { data: 0 };
              this.setNewNumber = this.setNewNumber.bind(this);
            }
    
            setNewNumber() {
              this.setState({ data: this.state.data + 1 });
            }
            render() {
              return (
                <div>
                  <button onClick={this.setNewNumber}>INCREMENT</button>
                  <Content myNumber={this.state.data}></Content>
                </div>
              );
            }
          }
    
          class Content extends React.Component {
            componentWillMount() {
              console.log("Component WILL MOUNT!");
            }
            componentDidMount() {
              console.log("Component DID MOUNT!");
            }
            componentWillReceiveProps(newProps) {
              console.log("Component WILL RECEIVE PROPS!");
            }
            shouldComponentUpdate(newProps, newState) {
              return true;
            }
            componentWillUpdate(nextProps, nextState) {
              console.log("Component WILL UPDATE!");
            }
            componentDidUpdate(prevProps, prevState) {
              console.log("Component DID UPDATE!");
            }
            componentWillUnmount() {
              console.log("Component WILL UNMOUNT!");
            }
    
            render() {
              return (
                <div>
                  <h3>{this.props.myNumber}</h3>
                </div>
              );
            }
          }
          ReactDOM.render(
            <div>
              <Button />
            </div>,
            document.getElementById("app")
          );
        script>
      body>
    html>
    
    
    • 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
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    在这里插入图片描述
    注意:只有类组件才有生命周期。函数组件每次都是重新运行函数,旧的组件即刻被销毁。

    2.4 函数式组件useEffect

    与使用state需要借助useState一样,在函数组件中,我们需要借助可以借助react提供的方法在函数式组件中实现“生命周期”,它就是useEffect

    useEffect 给函数组件增加了操作副作用的能力。它跟 class 组件中的
    componentDidMount、componentDidUpdate 和 componentWillUnmount
    具有相同的用途,只不过被合并成了一个 API。

    DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>useEffecttitle>
        <script src="https://cdn.staticfile.org/react/16.8.0/umd/react.development.js">script>
        <script src="https://cdn.staticfile.org/react-dom/16.8.0/umd/react-dom.development.js">script>
        
        <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js">script>
      head>
      <body>
        <div id="app">div>
        <script type="text/babel">
          const Clock = (props) => {
            const [n, setN] = React.useState(0);
            function addNum() {
              setN(n + 1);
            }
    
            React.useEffect(() => {
              console.log(n);
            });
    
            return (
              <div>
                <p>现在的n是 {n} .</p>
                <button onClick={addNum}>n+1</button>
              </div>
            );
          };
    
          ReactDOM.render(<Clock />, document.getElementById("app"));
        script>
      body>
    html>
    
    
    • 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

    在这里插入图片描述
    可以看到,上面的使用useEffect时,挂载或者销毁时,都会触发useEffect中的函数,那么如何使用useEffect模拟生命周期呢?

    //    只在组件挂载后显示,只需要加个空数组做参数即可
        useEffect(() => {
            document.title = `You clicked ${count} times`;
        },[]);
     
    //    销毁阶段
        useEffect(() => {
            return ()=>{
    				console.log("销毁阶段")
    			}
        });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    三、总结

    可以看到,类组件和函数组件在State和生命周期上区别还是非常大的,函数式组件需要调用react提供的hooks(钩子函数,非常重要,后面会专门学习)来实现类组件对于的功能。

    学习过程中,我发现react类组件类似于vue2的选项式api组件,而函数组件则vue3组合式api十分相似。

  • 相关阅读:
    设计模式之迭代器模式
    [SpringBoot]SpringBoot概述(简介、官网构建、快速启动)
    详解linux内核链表list_head及其接口应用
    JSP教师辅助办公软件教学进程管理系统yeclipse开发mysql数据库bs框架java编程jdbc详细设计
    图论学习笔记 - 最近公共祖先(LCA)
    8.1.2 创建数据表时指定主键
    Python远程SSH和HTTP视频流级联分类Raspberry Pi 机器人
    计算机竞赛 题目:基于深度学习的图像风格迁移 - [ 卷积神经网络 机器视觉 ]
    怎么强制粘贴密码进去
    上海建筑模板厂家:承载城市梦想的力量
  • 原文地址:https://blog.csdn.net/ZHANGYANG_1109/article/details/125885933