04-React 面向组件编程

98 阅读2分钟

React 面向组件编程

1-基本理解和使用

1.1-函数式组件

<!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>01-函数式组件</title>
  </head>
  <body>
    <!-- 准备好容器 -->
    <div id="test"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 1. 创建函数式组件
      function MyComponent(params) {
        console.log(this); // undefined  --->  是因为 babel 编译后是严格模式,那么this就不能指向window了,
        return <h2>我是用函数定义的组件(适用于简单组件的定义)</h2>;
      }
      // 2. 渲染组件到页面
      ReactDOM.render(<MyComponent />, document.getElementById("test"));
      /**
       * 执行了 ReactDOM.render(<MyComponent />, document.getElementById("test"));
       * 1. React会解析组件标签,找MyComponent组件
       * 2. 发现组件是函数定义的,那么就调用这个函数,
       * 3. 将返回的虚拟dom转换成真实dom.呈现在页面上
       */
    </script>
  </body>
</html>

1.2-类式组件

<!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>01-函数式组件</title>
  </head>
  <body>
    <!-- 准备好容器 -->
    <div id="test"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 1. 类式组件
      class MyComponent extends React.Component {
        render() {
          // render 方法放在了 ---> 类 MyComponent 的原型对象上; 供实例使用
          // render 的this是谁  --->  MyComponent 的实例对象
          console.log(this); // MyComponent {props: {…}, context: {…}, refs: {…}, updater: {…}, _reactInternalFiber: FiberNode, …}
          return <h1>我是类定义的组件,适用于复杂组件</h1>;
        }
      }
      // 2. 渲染组件到页面
      ReactDOM.render(<MyComponent />, document.getElementById("test"));
      /**
       * 执行了 ReactDOM.render(<MyComponent />, document.getElementById("test"));
       * 1. React会解析组件标签,找MyComponent组件
       * 2. 发现组件是函数定义的,那么就new出来该类的实例,并通过该实例调用到原型的render方法,
       * 3. 将返回的虚拟dom转换成真实dom.呈现在页面上
       */
    </script>
  </body>
</html>

02-state

2.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></title>
  </head>
  <body>
    <!-- 准备好容器 -->
    <div id="test"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 1. 创建组件
      class Weather extends React.Component {
        // constructor 构造器执行几次?-->new 几次就会执行几次
        constructor(props) {
          super(props);
          // 初始化状态
          this.state = {
            isHot: true,
            wind: "微风",
          };
          // 这样处理是为了解决静态方法内无法拿到类的this,解决this指向的问题
          this.changeWeather = this.changeWeather.bind(this);
        }
        /**
         * changeWeather放在哪里?---Watcher的原型对象上,供实例使用
         * 由于changeWeather方法作为onClick的回调,所以不是实例调用的而是直接调用的
         * 类中的方法默认开启了严格模式,所以changeWeather里面的this是undefined
         *
         */
        //  changeWeather 执行几次? ---> 点几次调用几次
        changeWeather() {
          const isHot = this.state.isHot;
          // state里面的状态里面的数据要修改需要使用 setState 方法
          // this.state.isHot = !isHot   // 错误的写法
          this.setState({
            isHot: !isHot,
          });
        }
        // render 执行几次?--> 执行 n+1 次, n 是状态更新的次数,每次 state 更新, render 都会执行
        render() {
          // 读取状态
          const { isHot, wind } = this.state;
          return (
            <div>
              <button onClick={this.changeWeather}>改变天气</button>
              <h1>
                今天的天气好: {isHot ? "热" : "冷"},{wind}
              </h1>
            </div>
          );
        }
      }
      // 2. 渲染组件到页面
      ReactDOM.render(<Weather />, document.getElementById("test"));
    </script>
  </body>
</html>

2.2-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></title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      class Weather extends React.Component {
        // 初始化状态
        state = { isHot: true, wind: "微风" };

        /**
         * 自定义方法:---以后都成 赋值语句的形式+箭头函数
         * this执行就会到了watcher了
         * 这样的写法就是把 changeWeather 放在自身,而不是放在原型函数上
         */
        changeWeather = () => {
          console.log(this); // Weather {props: {…}, context: {…}, refs: {…}, updater: {…}, state: {…}, …}
          const isHot = this.state.isHot;
          this.setState({ isHot: !isHot });
        };
        render() {
          const { isHot, wind } = this.state;
          return (
            <div>
              <h1 onClick={this.changeWeather}>
                今天的天气好: {isHot ? "热" : "冷"},{wind}
              </h1>
            </div>
          );
        }
      }
      // 2. 渲染组件到页面
      ReactDOM.render(<Weather />, document.getElementById("test"));
    </script>
  </body>
</html>

03-props

3.1-props 基本使用

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        render() {
          return (
            <ul>
              <li>姓名{this.props.name}</li>
              <li>年龄{this.props.age}</li>
              <li>性别{this.props.sex}</li>
            </ul>
          );
        }
      }
      // 2. 渲染组件到页面
      ReactDOM.render(
        <MyComponent name="tom" age="12" sex="男" />,
        document.getElementById("test")
      );
    </script>
  </body>
</html>

3.2-对 props 进行限制

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test"></div>
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 引入prop-types,用于对组件标签属性进行限制 -->
    <script src="../React-js/prop-types.js"></script>

    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        // props是只读的
        render() {
          return (
            <ul>
              <li>姓名{this.props.name}</li>
              <li>年龄{this.props.age}</li>
              <li>性别{this.props.sex}</li>
            </ul>
          );
        }
      }
      // 对标签属性进行必要性的限制
      MyComponent.propTypes = {
        name: PropTypes.string.isRequired, // 限制姓名为字符串且必填
        name: PropTypes.string, // 限制必须字符串
        age: PropTypes.number, // 限制必须数字
        speak: PropTypes.func, // 限制必须为函数
      };
      // 指定属性的默认值
      MyComponent.defaultProps = {
        sex: "不男不女",
        age: 18,
      };
      const info = { name: "123", age: 13 };
      ReactDOM.render(
        <MyComponent {...info} speak={speak} />,
        document.getElementById("test1")
      );
      function speak(params) {
        console.log("我说话了");
      }
    </script>
  </body>
</html>

3.3-props 简写

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test"></div>
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 引入prop-types,用于对组件标签属性进行限制 -->
    <script src="../React-js/prop-types.js"></script>

    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        // 对标签属性进行必要性的限制
        static propTypes = {
          name: PropTypes.string.isRequired, // 限制姓名为字符串且必填
          name: PropTypes.string, // 限制必须字符串
          age: PropTypes.number, // 限制必须数字
          speak: PropTypes.func, // 限制必须为函数
        };
        // 指定属性的默认值
        static defaultProps = {
          sex: "不男不女",
          age: 18,
        };
        // props是只读的
        render() {
          return (
            <ul>
              <li>姓名{this.props.name}</li>
              <li>年龄{this.props.age}</li>
              <li>性别{this.props.sex}</li>
            </ul>
          );
        }
      }

      const info = { name: "123", age: 13 };
      ReactDOM.render(
        <MyComponent {...info} speak={speak} />,
        document.getElementById("test1")
      );
      function speak(params) {
        console.log("我说话了");
      }
    </script>
  </body>
</html>

3.4-props 在构造函数中情况

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test"></div>
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 引入prop-types,用于对组件标签属性进行限制 -->
    <script src="../React-js/prop-types.js"></script>

    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        // props是只读的
        render() {
          return (
            <ul>
              <li>姓名{this.props.name}</li>
              <li>年龄{this.props.age}</li>
              <li>性别{this.props.sex}</li>
            </ul>
          );
        }
      }
      const info = { name: "123", age: 13 };
      ReactDOM.render(
        <MyComponent {...info} speak={speak} />,
        document.getElementById("test1")
      );
      function speak(params) {
        console.log("我说话了");
      }
    </script>
  </body>
</html>

3.5-props 在函数值组件中使用

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test"></div>
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 引入prop-types,用于对组件标签属性进行限制 -->
    <script src="../React-js/prop-types.js"></script>

    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 1. 创建函数式组件
      function MyComponent(props) {
        const { name, age, sex } = props;
        return (
          <ul>
            <li>姓名{name}</li>
            <li>年龄{age}</li>
            <li>性别{sex}</li>
          </ul>
        );
      }
      // 对标签属性进行必要性的限制
      MyComponent.propTypes = {
        name: PropTypes.string.isRequired, // 限制姓名为字符串且必填
        name: PropTypes.string, // 限制必须字符串
        age: PropTypes.number, // 限制必须数字
        speak: PropTypes.func, // 限制必须为函数
      };
      // 指定属性的默认值
      MyComponent.defaultProps = {
        sex: "不男不女",
        age: 18,
      };
      const info = { name: "123", age: 13 };
      ReactDOM.render(
        <MyComponent {...info} />,
        document.getElementById("test1")
      );
    </script>
  </body>
</html>

04-refs

4.1-字符串形式 refs 的基本使用

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test"></div>
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      /**
       * 字符串的refs存在效率上的问题,不推荐使用
       */
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        // 展示左侧输入框的数据
        showData = () => {
          const { input1 } = this.refs;
          let value1 = input1.value;
          console.log(value1);
        };
        // 展示右侧输入框的数据
        showData2 = () => {
          const { input2 } = this.refs;
          let value2 = input2.value;
          console.log(value2);
        };
        render() {
          return (
            <div>
              <input
                ref="input1"
                type="text"
                placeholder="点击按钮提示数据"
              ></input>
              <button onClick={this.showData}>点我提示左侧的数据</button>
              <input
                ref="input2"
                onBlur={this.showData2}
                type="text"
                placeholder="失去焦点提示数据"
              ></input>
            </div>
          );
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(<MyComponent />, document.getElementById("test1"));
    </script>
  </body>
</html>

4.2-回调形式 refs 的基本使用

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test"></div>
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      /**
       * 字符串的refs存在效率上的问题,不推荐使用
       */
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        // 展示左侧输入框的数据
        showData = () => {
          const { input1 } = this;
          let value1 = input1.value;
          alert(value1);
        };
        // 展示右侧输入框的数据
        showData2 = () => {
          const { input2 } = this;
          let value2 = input2.value;
          alert(value2);
        };
        render() {
          return (
            <div>
              <input
                ref={(c) => (this.input1 = c)}
                type="text"
                placeholder="点击按钮提示数据"
              ></input>
              <button onClick={this.showData}>点我提示左侧的数据</button>
              <input
                ref={(c) => (this.input2 = c)}
                onBlur={this.showData2}
                type="text"
                placeholder="失去焦点提示数据"
              ></input>
            </div>
          );
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(<MyComponent />, document.getElementById("test1"));
    </script>
  </body>
</html>

4.3-回调形式 refs 的回调执行次数

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test"></div>
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      /**
       * 字符串的refs存在效率上的问题,不推荐使用
       */
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        state = { isHot: true };
        // 展示左侧输入框的数据
        showData = () => {
          const { input1 } = this;
          let value1 = input1.value;
          alert(value1);
        };
        changeWeather = () => {
          const { isHot } = this.state;
          this.setState({
            isHot: !isHot,
          });
        };
        saveInput = (c) => {
          this.input1 = c;
          console.log(c);
        };
        render() {
          const { isHot } = this.state;
          return (
            <div>
              <h2>今天天气很{isHot ? "热" : "冷"}</h2>
              {/*这种写法有个问题,就是更新时候,这个console.log(c)会执行两次,第一次c是null,第二才是这个dom结构*/}
              {/*<input ref={c => { this.input1 = c; console.log(c); }} type="text" placeholder="点击按钮提示数据"></input>*/}

              {/*这种写法是做好的,只会执行一次,但是没必要*/}
              <input
                ref={this.saveInput}
                type="text"
                placeholder="点击按钮提示数据"
              ></input>
              <button onClick={this.showData}>点我提示左侧的数据</button>
              <button onClick={this.changeWeather}>点我切换天气</button>
            </div>
          );
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(<MyComponent />, document.getElementById("test1"));
    </script>
  </body>
</html>

4.4-createRef 形式 refs 的基本使用

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test"></div>
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        /**
         * React.createRef调用后返回䘝容器,该容器可以存储被ref所标识的节点
         * 该容器是专人专用,只能存一个节点
         */
        myRef1 = React.createRef();
        myRef2 = React.createRef();
        // 展示左侧输入框的数据
        showData = () => {
          alert(this.myRef1.current.value);
        };
        // 展示右侧输入框的数据
        showData2 = () => {
          alert(this.myRef2.current.value);
        };
        render() {
          return (
            <div>
              <input
                ref={this.myRef1}
                type="text"
                placeholder="点击按钮提示数据"
              ></input>
              <button onClick={this.showData}>点我提示左侧的数据</button>
              <input
                ref={this.myRef2}
                onBlur={this.showData2}
                type="text"
                placeholder="失去焦点提示数据"
              ></input>
            </div>
          );
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(<MyComponent />, document.getElementById("test1"));
    </script>
  </body>
</html>

4.5-.事件处理

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test"></div>
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        /**
         * 1. 通过 onXxx 属性指定事件处理函数(注意大小写)
         *   1.1 React 使用的是自定义(合成)事件,而不是使用的原生DOM的事件 --- 为了更好的兼容性
         *   1.2 React 中的事件是通过事件委托方式处理的(委托给组件的最外层) --- 为了高效
         * 2. 通过 event.target 得到发生事件的 DOM 元素 --- 不要过度使用 ref
         */

        //创建ref容器
        myRef1 = React.createRef();
        // 展示左侧输入框的数据
        showData = () => {
          alert(this.myRef1.current.value);
        };
        // 展示右侧输入框的数据
        showData2 = (event) => {
          alert(event.target.value);
        };
        render() {
          return (
            <div>
              <input
                ref={this.myRef1}
                type="text"
                placeholder="点击按钮提示数据"
              ></input>
              <button onClick={this.showData}>点我提示左侧的数据</button>
              <input
                onBlur={this.showData2}
                type="text"
                placeholder="失去焦点提示数据"
              ></input>
            </div>
          );
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(<MyComponent />, document.getElementById("test1"));
    </script>
  </body>
</html>

5-React 中收集表单数据

5.1-非受控组件

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test"></div>
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        handleSubmit = (e) => {
          const { username, password } = this;
          e.preventDefault(); // 可以阻止表单的默认跳转
          console.log(username.value, password.value);
        };
        render() {
          return (
            <form onSubmit={this.handleSubmit}>
              用户名:{" "}
              <input
                ref={(c) => (this.username = c)}
                type="text"
                name="username"
              />
              密码: <input
                ref={(c) => (this.password = c)}
                type="password"
                password="password"
              />
              <button>登录</button>
            </form>
          );
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(<MyComponent />, document.getElementById("test1"));
    </script>
  </body>
</html>

5.2-受控组件

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test"></div>
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      /**
       * 手控组件的好处就是省掉了过多的ref
       */
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        state = {
          username: "",
          password: "",
        };
        handleSubmit = (e) => {
          e.preventDefault(); // 可以阻止表单的默认跳转
          const { username, password } = this.state;
          console.log(username, password);
        };
        // 保存用户名到state
        changeUsername = (e) => {
          this.setState({ username: e.target.value });
        };
        // 保存密码到state
        changePassword = (e) => {
          this.setState({ password: e.target.value });
        };
        render() {
          return (
            <form onSubmit={this.handleSubmit}>
              用户名:{" "}
              <input
                onChange={this.changeUsername}
                type="text"
                name="username"
              />
              密码: <input
                onChange={this.changePassword}
                type="password"
                password="password"
              />
              <button>登录</button>
            </form>
          );
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(<MyComponent />, document.getElementById("test1"));
    </script>
  </body>
</html>

6-高阶函数与函数柯里化

6.1-高阶函数和函数柯里化

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test"></div>
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      /**
       * 高阶函数: 如果一个函数符合下面两个规范中的任何一个,那么该函数就是高阶函数
       *      1. 若A函数,接收的参数是一个函数,那么A函数就称为高阶函数
       *      2. 若A函数,调用的返回值依然是一个函数,那么A函数就称为高阶函数
       * 常见的高阶函数
       *      1. Promise    new Promise(()=>{})
       *      2. setTimeout
       *      3. arr.map 等等
       *
       *
       * 函数的柯里化: 通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码方式
       */
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        state = {
          username: "",
          password: "",
        };
        // 提交表单
        handleSubmit = (event) => {
          event.preventDefault(); // 可以阻止表单的默认跳转
          const { username, password } = this.state;
          console.log(username, password);
        };
        // 保存表单项的数据到状态中
        saveFormData = (dataType) => {
          return (event) => {
            this.setState({ [dataType]: event.target.value });
          };
        };
        render() {
          return (
            <form onSubmit={this.handleSubmit}>
              用户名:{" "}
              <input
                onChange={this.saveFormData("username")}
                type="text"
                name="username"
              />
              密码: <input
                onChange={this.saveFormData("password")}
                type="password"
                password="password"
              />
              <button>登录</button>
            </form>
          );
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(<MyComponent />, document.getElementById("test1"));
    </script>
  </body>
</html>

6.2-不用高阶函数和函数柯里化

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test"></div>
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        state = {
          username: "",
          password: "",
        };
        // 提交表单
        handleSubmit = (event) => {
          event.preventDefault(); // 可以阻止表单的默认跳转
          const { username, password } = this.state;
          console.log(username, password);
        };
        // 保存表单项的数据到状态中
        saveFormData = (dataType, event) => {
          this.setState({ [dataType]: event.target.value });
        };
        render() {
          return (
            <form onSubmit={this.handleSubmit}>
              用户名:{" "}
              <input
                onChange={(event) => {
                  this.saveFormData("username", event);
                }}
                type="text"
                name="username"
              />
              密码: <input
                onChange={(event) => {
                  this.saveFormData("password", event);
                }}
                type="password"
                password="password"
              />
              <button>登录</button>
            </form>
          );
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(<MyComponent />, document.getElementById("test1"));
    </script>
  </body>
</html>

7-组件的生命周期

旧生命周期

旧生命周期

新生命周期

7-1.引出生命周期

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test"></div>
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 生命周期回调函数 === 生命周期钩子函数 === 生周期函数 === 生命周期钩子
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        state = { opacity: 1 };
        death = () => {
          // 卸载组件
          ReactDOM.unmountComponentAtNode(document.getElementById("test1"));
        };
        // 组件挂在完毕时候调用
        componentDidMount() {
          this.timer = setInterval(() => {
            let { opacity } = this.state;
            opacity -= 0.1;
            if (opacity <= 0) {
              opacity = 1;
            }
            this.setState({ opacity });
          }, 200);
        }
        // 组件将要卸载时候调用
        componentWillUnmount() {
          clearInterval(this.timer);
        }
        // 初始化渲染, 状态更新之后
        render() {
          return (
            <div>
              <h2 style={{ opacity: this.state.opacity }}>
                React学不会怎么办?
              </h2>
              <button onClick={this.death}>不活了!</button>
            </div>
          );
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(<MyComponent />, document.getElementById("test1"));
    </script>
  </body>
</html>

7-2.生命周期-挂载(旧)

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 生命周期回调函数 === 生命周期钩子函数 === 生周期函数 === 生命周期钩子
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        // 构造器 (第一步)
        constructor(props) {
          super(props);
          // 初始化状态
          this.state = { count: 0 };
          console.log("挂载 第一步 ---> constructor");
        }
        death = () => {
          ReactDOM.unmountComponentAtNode(document.getElementById("test1"));
        };
        // 组件将要挂载时候调用 (第二步)
        componentWillMount() {
          console.log("挂载 第二步 ---> componentWillMount");
        }
        // 初始化渲染, 状态更新之后
        render() {
          console.log("挂载 第三步 ---> render");
          return (
            <div>
              <h2>当前求和为: {this.state.count}</h2>
              <button onClick={this.death}>卸载组件</button>
            </div>
          );
        }
        // 组件挂载完毕时候调用
        componentDidMount() {
          console.log("挂载 第四步 ---> componentDidMount");
        }
        // 组件将要卸载时候调用
        componentWillUnmount() {
          console.log("挂载 第五步 ---> componentWillUnmount");
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(<MyComponent />, document.getElementById("test1"));
    </script>
  </body>
</html>

7-3.生命周期-setState 更新(旧)

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 生命周期回调函数 === 生命周期钩子函数 === 生周期函数 === 生命周期钩子
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        // 构造器 (第一步)
        constructor(props) {
          super(props);
          // 初始化状态
          this.state = { count: 0 };
        }
        add = () => {
          const { count } = this.state;
          this.setState({
            count: count + 1,
          });
          console.log("更新 第一步 ---> setState");
        };
        // 控制组件更新的开关
        shouldComponentUpdate() {
          console.log("更新 第二步 ---> shouldComponentUpdate");
          return true;
        }
        componentWillUpdate() {
          console.log("更新 第三步 ---> componentWillUpdate");
        }
        // 初始化渲染, 状态更新之后
        render() {
          console.log("更新 第四步 ---> render");
          return (
            <div>
              <h2>当前求和为: {this.state.count}</h2>
              <button onClick={this.add}>点我+1</button>
            </div>
          );
        }
        componentDidUpdate() {
          console.log("更新 第五步 ---> componentDidUpdate");
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(<MyComponent />, document.getElementById("test1"));
    </script>
  </body>
</html>

7-4.生命周期-forceUpdate 更新(旧)

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 生命周期回调函数 === 生命周期钩子函数 === 生周期函数 === 生命周期钩子
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        // 构造器 (第一步)
        constructor(props) {
          super(props);
          // 初始化状态
          this.state = { count: 0 };
        }
        // 强制更新按钮(不会走到shouldComponentUpdate)
        force = () => {
          this.forceUpdate();
          console.log("更新 第一步 ---> forceUpdate");
        };
        componentWillUpdate() {
          console.log("更新 第二步 ---> componentWillUpdate");
        }
        // 初始化渲染, 状态更新之后
        render() {
          console.log("更新 第三步 ---> render");
          return (
            <div>
              <h2>当前求和为: {this.state.count}</h2>
              <button onClick={this.force}>不更新数据强制更新页面</button>
            </div>
          );
        }
        componentDidUpdate() {
          console.log("更新 第四步 ---> componentDidUpdate");
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(<MyComponent />, document.getElementById("test1"));
    </script>
  </body>
</html>

7-5.生命周期-父组件 render 更新(旧)

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 生命周期回调函数 === 生命周期钩子函数 === 生周期函数 === 生命周期钩子
      // 父组件A
      class A extends React.Component {
        state = { carName: "奔驰" };
        changeCar = () => {
          this.setState({ carName: "奥迪" });
        };
        render() {
          return (
            <div>
              <h1>A</h1>
              <button onClick={this.changeCar}>换车</button>
              <B carName={this.state.carName} />
            </div>
          );
        }
      }
      // 子组件B
      class B extends React.Component {
        // 这个钩子第一次传的不算
        componentWillReceiveProps(props) {
          console.log("子组件更新 第一步 ---> componentWillReceiveProps");
          console.log(props);
        }
        // 控制组件更新的开关
        shouldComponentUpdate() {
          console.log("子组件更新 第二步 ---> shouldComponentUpdate");
          return true;
        }
        componentWillUpdate() {
          console.log("子组件更新 第三步 ---> componentWillUpdate");
        }
        render() {
          console.log("子组件更新 第四步 ---> render");
          return <div>B -- {this.props.carName}</div>;
        }
        componentDidUpdate() {
          console.log("子组件更新 第五步 ---> componentDidUpdate");
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(<A />, document.getElementById("test1"));
    </script>
  </body>
</html>

7-6.生命周期总结(旧)

/**
 * 常用:
 *      1. componentDidMount() 一般做一些初始化的事儿,例如开始定制器或者发送网络请求或者订阅消息
 *      2. componentWillUnmount() 一般做一些收尾的事儿,例如取消定时器
 *
 * 1. 初始化阶段: 由 ReactDOM.render() 触发---初次渲染
 *      1. constructor()
 *      2. componentWillMount()
 *      3. render()
 *      4. componentDidMount()
 * 2. 更新阶段: 由组件内部 setState() 或者父组件 render() 触发
 *      1. shouldComponentUpdate()
 *      2. componentWillUpdate()
 *      3. render()
 *      4. componentDidMount()
 * 3. 更新阶段: 由组件内部 forceUpdate() 触发
 *      1. componentWillUpdate()
 *      2. render()
 *      3. componentDidMount()
 * 4. 父组件Props更新: 由父组件Props更新导致子组件更新
 *      1. componentWillReceiveProps()
 *      2. shouldComponentUpdate()
 *      3. componentWillUpdate()
 *      4. render()
 *      5. componentDidMount()
 * 5. 卸载组件: 由 ReactDOM.unmountComponentAtNode() 触发
 *      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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 生命周期回调函数 === 生命周期钩子函数 === 生周期函数 === 生命周期钩子
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        // 构造器 (第一步)
        constructor(props) {
          super(props);
          // 初始化状态
          this.state = { count: 0 };
          console.log("挂载 第一步 ---> constructor");
        }
        death = () => {
          ReactDOM.unmountComponentAtNode(document.getElementById("test1"));
        };
        // 组件将要挂载时候调用 (第二步)
        componentWillMount() {
          console.log("挂载 第二步 ---> componentWillMount");
        }
        // 初始化渲染, 状态更新之后
        render() {
          console.log("挂载 第三步 ---> render");
          return (
            <div>
              <h2>当前求和为: {this.state.count}</h2>
              <button onClick={this.death}>卸载组件</button>
            </div>
          );
        }
        // 组件挂载完毕时候调用
        componentDidMount() {
          console.log("挂载 第四步 ---> componentDidMount");
        }
        // 组件将要卸载时候调用
        componentWillUnmount() {
          console.log("挂载 第五步 ---> componentWillUnmount");
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(<MyComponent />, document.getElementById("test1"));
    </script>
  </body>
</html>

7-7.生命周期-挂载(新)

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/17/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/17/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 所有带 will 的钩子函数都需要加上 UNSAFE_
      // 1. 创建函数式组件
      /***
       * 更新了三个钩子函数
       * 1. componentWillMount UNSAFE_componentWillMount
       * 2. componentWillUpdate UNSAFE_componentWillUpdate
       * 3. componentWillReceiveProps componentWillReceiveProps
       */
      class MyComponent extends React.Component {
        // 构造器 (第一步)
        constructor(props) {
          super(props);
          // 初始化状态
          this.state = { count: 0 };
          console.log("挂载 第一步 ---> constructor");
        }
        death = () => {
          ReactDOM.unmountComponentAtNode(document.getElementById("test1"));
        };
        // 组件将要挂载时候调用 - 旧 (第二步)
        componentWillMount() {
          console.log("挂载 第二步 ---> componentWillMount");
        }
        // 组件将要挂载时候调用 - 新 (第二步)
        UNSAFE_componentWillMount() {
          console.log("挂载 第二步 ---> UNSAFE_componentWillMount");
        }
        // 组件将要更新数据时调用 - 旧
        componentWillUpdate() {
          console.log("子组件更新 第三步 ---> componentWillUpdate");
        }
        // 组件将要更新数据时调用 - 新
        UNSAFE_componentWillUpdate() {
          console.log("子组件更新 第三步 ---> UNSAFE_componentWillUpdate");
        }
        // 当props发生变化时调用 - 旧
        // 这个钩子第一次传的不算
        componentWillReceiveProps(props) {
          console.log("子组件更新 第一步 ---> componentWillReceiveProps");
          console.log(props);
        }
        // 当props发生变化时调用 - 新
        // 这个钩子第一次传的不算
        UNSAFE_componentWillReceiveProps(props) {
          console.log(
            "子组件更新 第一步 ---> UNSAFE_componentWillReceiveProps"
          );
          console.log(props);
        }
        // 初始化渲染, 状态更新之后
        render() {
          console.log("挂载 第三步 ---> render");
          return (
            <div>
              <h2>当前求和为: {this.state.count}</h2>
              <button onClick={this.death}>卸载组件</button>
            </div>
          );
        }
        // 组件挂载完毕时候调用
        componentDidMount() {
          console.log("挂载 第四步 ---> componentDidMount");
        }
        // 组件将要卸载时候调用
        componentWillUnmount() {
          console.log("挂载 第五步 ---> componentWillUnmount");
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(<MyComponent />, document.getElementById("test1"));
    </script>
  </body>
</html>

7-8.生命周期-getDerivedStateFromProps(新)

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/17/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/17/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 所有带 will 的钩子函数都需要加上 UNSAFE_
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        // 构造器 (第一步)
        constructor(props) {
          super(props);
          // 初始化状态
          this.state = { count: 0 };
          console.log("挂载 第一步 ---> constructor");
        }
        death = () => {
          ReactDOM.unmountComponentAtNode(document.getElementById("test1"));
        };
        // 如果State的任何值都取决于Props,那么就可以使用这个,但是非必须使用
        // 会在调用 render 方法之前调用,
        // 即在渲染 DOM 元素之前会调用,并且在初始挂载及后续更新时都会被调用.
        static getDerivedStateFromProps(props, state) {
          console.log("props", props); // {count: 199}
          console.log("state", state); // {count: 0}
          console.log("挂载 第二步 ---> getDerivedStateFromProps");
          // 每次更新也会走到这里, 那么每次都会return这个数据, 则页面的数据一直不会改变
          // 都会展示 Props 的值
          return props; // 返回 State 则会影响 State
        }
        // 初始化渲染, 状态更新之后
        render() {
          console.log("挂载 第三步 ---> render");
          return (
            <div>
              <h2>当前求和为: {this.state.count}</h2>
              <button onClick={this.death}>卸载组件</button>
            </div>
          );
        }
        // 组件挂载完毕时候调用
        componentDidMount() {
          console.log("挂载 第四步 ---> componentDidMount");
        }
        // 组件将要卸载时候调用
        componentWillUnmount() {
          console.log("挂载 第五步 ---> componentWillUnmount");
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(
        <MyComponent count={199} />,
        document.getElementById("test1")
      );
    </script>
  </body>
</html>

7-9.生命周期-getSnapshotBeforeUpdate(新)

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/17/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/17/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 所有带 will 的钩子函数都需要加上 UNSAFE_
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        // 构造器 (第一步)
        constructor(props) {
          super(props);
          // 初始化状态
          this.state = { count: 0 };
          console.log("挂载 第一步 ---> constructor");
        }
        death = () => {
          ReactDOM.unmountComponentAtNode(document.getElementById("test1"));
        };
        update = () => {
          this.setState({ count: 1 });
        };
        /**
         * getSnapshotBeforeUpdate() 方法在最近一次渲染输出(提交到 DOM 节点)之前调用.
         * 在 getSnapshotBeforeUpdate() 方法中,我们可以访问更新前的 props 和 state.
         * getSnapshotBeforeUpdate() 方法需要与 componentDidUpdate() 方法一起使用,否则会出现错误.
         *
         * 组件更新完成前做一些操作
         */
        getSnapshotBeforeUpdate() {
          console.log("更新 第二步 ---> getSnapshotBeforeUpdate");
          return "getSnapshotBeforeUpdate";
        }
        // 初始化渲染, 状态更新之后
        render() {
          console.log("挂载 第三步 ---> render");
          console.log("更新 第一步 ---> getSnapshotBeforeUpdate");
          return (
            <div>
              <h2>当前求和为: {this.state.count}</h2>
              <button onClick={this.death}>卸载组件</button>
              <button onClick={this.update}>更新数据</button>
            </div>
          );
        }
        // 组件挂载完毕时候调用
        componentDidUpdate(preProps, preState, snapValue) {
          // 这俩哥参数都是修改之前的
          console.log(preProps, preState); // {count: 199} {count: 0}

          // 这个是 上个周期 getSnapshotBeforeUpdate 传过来的 snapValue
          console.log("getSnapshotBeforeUpdate传过来的数据--->", snapValue); // getSnapshotBeforeUpdate
          console.log("更新 第三步 ---> componentDidUpdate");
        }
        // 组件挂载完毕时候调用
        componentDidMount() {
          console.log("挂载 第四步 ---> componentDidMount");
        }
        // 组件将要卸载时候调用
        componentWillUnmount() {
          console.log("挂载 第五步 ---> componentWillUnmount");
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(
        <MyComponent count={199} />,
        document.getElementById("test1")
      );
    </script>
  </body>
</html>

7-10.getSnapshotBeforeUpdate 使用场景

<!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>01-函数式组件</title>
    <style>
      .list {
        width: 200px;
        height: 150px;
        background-color: yellow;
        overflow: auto;
      }

      .news {
        height: 30px;
      }
    </style>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/17/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/17/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      // 所有带 will 的钩子函数都需要加上 UNSAFE_
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        // 构造器 (第一步)
        constructor(props) {
          super(props);
          // 初始化状态
          this.state = { newsArr: [] };
        }
        componentDidMount() {
          setInterval(() => {
            const { newsArr } = this.state;
            const news = "新闻" + (newsArr.length + 1);
            this.setState({ newsArr: [news, ...newsArr] });
          }, 1000);
        }
        getSnapshotBeforeUpdate() {
          return this.refs.list.scrollHeight;
        }
        // 初始化渲染, 状态更新之后
        render() {
          return (
            <div className="list" ref="list">
              {this.state.newsArr.map((el) => {
                return (
                  <div key={el} className="news">
                    {el}
                  </div>
                );
              })}
            </div>
          );
        }
        // 组件挂载完毕时候调用
        componentDidUpdate(preProps, preState, height) {
          this.refs.list.scrollTop += this.refs.list.scrollHeight - height;
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(
        <MyComponent count={199} />,
        document.getElementById("test1")
      );
    </script>
  </body>
</html>

7-11.生命周期总结(新)

<!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>01-函数式组件</title>
  </head>

  <body>
    <!-- 准备好容器 -->
    <div id="test1"></div>
    <!-- 引入React核心库. -->
    <script src="../React-js/17/react.development.js"></script>
    <!-- 引入React-dom,用于支持操作DOM -->
    <script src="../React-js/17/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转为js -->
    <script src="../React-js/babel.min.js"></script>
    <!-- 写这个type的意义是为了让他知道我写的是jsx -->
    <script type="text/babel">
      /**
       * 常用:
       *      1. componentDidMount() 一般做一些初始化的事儿,例如开始定制器或者发送网络请求或者订阅消息
       *      2. componentWillUnmount() 一般做一些收尾的事儿,例如取消定时器
       *
       * 1. 初始化阶段: 由 ReactDOM.render() 触发---初次渲染
       *      1. constructor()
       *      2. getDerivedStateFromProps()
       *      3. render()
       *      4. componentDidMount()
       * 2. 更新阶段: 由组件内部 setState() 或者父组件 render() 触发
       *      1. getDerivedStateFromProps()
       *      2. shouldComponentUpdate()
       *      3. render()
       *      4. getSnapshotBeforeUpdate()
       *      4. componentWillUpdate()
       * 3. 卸载组件: 由 ReactDOM.unmountComponentAtNode() 触发
       *      1. componentWillUnmount()
       */
      // 所有带 will 的钩子函数都需要加上 UNSAFE_
      // 1. 创建函数式组件
      class MyComponent extends React.Component {
        // 构造器 (第一步)
        constructor(props) {
          super(props);
          // 初始化状态
          this.state = { count: 0 };
          console.log("挂载 第一步 ---> constructor");
        }
        death = () => {
          ReactDOM.unmountComponentAtNode(document.getElementById("test1"));
        };
        update = () => {
          this.setState({ count: 1 });
        };
        /**
         * getSnapshotBeforeUpdate() 方法在最近一次渲染输出(提交到 DOM 节点)之前调用.
         * 在 getSnapshotBeforeUpdate() 方法中,我们可以访问更新前的 props 和 state.
         * getSnapshotBeforeUpdate() 方法需要与 componentDidUpdate() 方法一起使用,否则会出现错误.
         *
         * 组件更新完成前做一些操作
         */
        getSnapshotBeforeUpdate() {
          console.log("更新 第二步 ---> getSnapshotBeforeUpdate");
          return "getSnapshotBeforeUpdate";
        }
        // 初始化渲染, 状态更新之后
        render() {
          console.log("挂载 第三步 ---> render");
          console.log("更新 第一步 ---> getSnapshotBeforeUpdate");
          return (
            <div>
              <h2>当前求和为: {this.state.count}</h2>
              <button onClick={this.death}>卸载组件</button>
              <button onClick={this.update}>更新数据</button>
            </div>
          );
        }
        // 组件挂载完毕时候调用
        componentDidUpdate(preProps, preState, snapValue) {
          // 这俩哥参数都是修改之前的
          console.log(preProps, preState); // {count: 199} {count: 0}

          // 这个是 上个周期 getSnapshotBeforeUpdate 传过来的 snapValue
          console.log("getSnapshotBeforeUpdate传过来的数据--->", snapValue); // getSnapshotBeforeUpdate
          console.log("更新 第三步 ---> componentDidUpdate");
        }
        // 组件挂载完毕时候调用
        componentDidMount() {
          console.log("挂载 第四步 ---> componentDidMount");
        }
        // 组件将要卸载时候调用
        componentWillUnmount() {
          console.log("挂载 第五步 ---> componentWillUnmount");
        }
      }
      // 2.渲染组件到页面
      ReactDOM.render(
        <MyComponent count={199} />,
        document.getElementById("test1")
      );
    </script>
  </body>
</html>