03_React 收集表单数据和 组件生命周期

React 收集表单数据和 组件生命周期

一、收集表单数据

1、例子

1.1 需求:定义一个包含表单的组件,输入用户名密码后,点击登录提示输入信息
html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>收集表单数据</title>
  </head>
  <body>
    <div id="test"></div>
    <!-- 引入 react 核心库 -->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- 引入 react-dom,用于支持 react 操作DOM -->
    <script
      type="text/javascript"
      src="../js/react-dom.development.js"
    ></script>
    <!-- 引入babel, 用于将 jsx 转为 js -->
    <script type="text/javascript" src="../js/babel.min.js"></script>

    <!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <!-- 此处一定要写babel -->
    <script type="text/babel">
      // 1、创建组件
      class Login extends React.Component {
        render() {
          return (
            <form action="xxx" onSubmit={this.submit}>
              用户名:
              <input
                type="text"
                ref={(c) => {
                  this.username = c
                }}
                placeholder="用户名"
                name="username"
              />
              <br />
              密码:
              <input
                type="password"
                ref={(c) => {
                  this.password = c
                }}
                placeholder="密码"
                name="password"
              />
              <button>登录</button>
            </form>
          )
        }
        submit = (e) => {
          e.preventDefault()
          let { password, username } = this
          console.log(password.value, username.value)
        }
      }
      // 2、渲染组件到页面
      // ReactDOM.render(组件,容器)
      ReactDOM.render(<Login />, document.getElementById('test'))
    </script>
  </body>
</html>

2、理解:包含表单的组件分类

2.1 受控组件

页面中所有的输入类的节点,随着输入将数据维护到状态中,使用的时候直接从状态中取,就是受控组件

受控组件的优势在于 可以减少 ref 的使用

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>受控组件</title>
  </head>
  <body>
    <div id="test"></div>
    <!-- 引入 react 核心库 -->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- 引入 react-dom,用于支持 react 操作DOM -->
    <script
      type="text/javascript"
      src="../js/react-dom.development.js"
    ></script>
    <!-- 引入babel, 用于将 jsx 转为 js -->
    <script type="text/javascript" src="../js/babel.min.js"></script>

    <!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <!-- 此处一定要写babel -->
    <script type="text/babel">
      // 1、创建组件
      class Login extends React.Component {
        // 初始化状态
        state = {
          username: '',
          password: '',
        }
        render() {
          return (
            <form action="xxx" onSubmit={this.submit}>
              用户名:
              <input
                type="text"
                onChange={this.saveUsername}
                placeholder="用户名"
                name="username"
              />
              <br />
              密码:
              <input
                type="password"
                onChange={this.savePassword}
                placeholder="密码"
                name="password"
              />
              <button>登录</button>
            </form>
          )
        }
        // 保存用户名到状态中
        saveUsername = (event) => {
          this.setState({ username: event.target.value })
        }
        // 保存密码到状态中
        savePassword = (event) => {
          this.setState({ password: event.target.value })
        }
        // 表单提交回调
        submit = (e) => {
          e.preventDefault()
          let { password, username } = this.state
          console.log(password, username)
        }
      }
      // 2、渲染组件到页面
      // ReactDOM.render(组件,容器)
      ReactDOM.render(<Login />, document.getElementById('test'))
    </script>
  </body>
</html>
2.2 非受控组件

页面中所有的输入类的节点,现用现取就是 非受控组件

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>收集表单数据</title>
  </head>
  <body>
    <div id="test"></div>
    <!-- 引入 react 核心库 -->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- 引入 react-dom,用于支持 react 操作DOM -->
    <script
      type="text/javascript"
      src="../js/react-dom.development.js"
    ></script>
    <!-- 引入babel, 用于将 jsx 转为 js -->
    <script type="text/javascript" src="../js/babel.min.js"></script>

    <!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <!-- 此处一定要写babel -->
    <script type="text/babel">
      // 1、创建组件
      class Login extends React.Component {
        render() {
          return (
            <form action="xxx" onSubmit={this.submit}>
              用户名:
              <input
                type="text"
                ref={(c) => {
                  this.username = c
                }}
                placeholder="用户名"
                name="username"
              />
              <br />
              密码:
              <input
                type="password"
                ref={(c) => {
                  this.password = c
                }}
                placeholder="密码"
                name="password"
              />
              <button>登录</button>
            </form>
          )
        }
        submit = (e) => {
          e.preventDefault()
          let { password, username } = this
          console.log(password.value, username.value)
        }
      }
      // 2、渲染组件到页面
      // ReactDOM.render(组件,容器)
      ReactDOM.render(<Login />, document.getElementById('test'))
    </script>
  </body>
</html>

二、高阶函数_函数柯里化

1、复习--对象相关的知识

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script type="text/javascript">
      let a = 'name'
      let obj = {} // {name: 'Tom'}
      obj[a] = 'Tom'
      console.log(obj)
    </script>
  </body>
</html>

2、高阶函数

如果一个函数符合下面 2 个规范中任何一个,那么该函数就是高阶函数

1)若 A 函数,接收的参数是一个函数,那么 A 就可以称为高阶函数

2)若 A 函数,调用的返回值依然是一个函数,那么 A 就可以称之为高阶函数

常见的高阶函数: arr.map()、arr.filter()、Promise、arr.find()、arr.reduce()、setTimout 等等

下面代码中的 saveFormData 函数就是一个高阶函数,符合了条件 2(返回值是一个函数)

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>高阶函数_函数柯里化</title>
  </head>
  <body>
    <div id="test"></div>
    <!-- 引入 react 核心库 -->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- 引入 react-dom,用于支持 react 操作DOM -->
    <script
      type="text/javascript"
      src="../js/react-dom.development.js"
    ></script>
    <!-- 引入babel, 用于将 jsx 转为 js -->
    <script type="text/javascript" src="../js/babel.min.js"></script>

    <!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <!-- 此处一定要写babel -->
    <script type="text/babel">
      // 1、创建组件
      class Login extends React.Component {
        // 初始化状态
        state = {
          username: '',
          password: '',
        }
        render() {
          return (
            <form action="xxx" onSubmit={this.submit}>
              用户名:
              <input
                type="text"
                onChange={this.saveFormData('username')}
                placeholder="用户名"
                name="username"
              />
              <br />
              密码:
              <input
                type="password"
                onChange={this.saveFormData('password')}
                placeholder="密码"
                name="password"
              />
              <button>登录</button>
            </form>
          )
        }
        // 保存表单数据到状态中
        saveFormData = (dataType) => {
          // 把此函数交给 react 处理,react 可以传入一个 event
          return (event) => {
            console.log(dataType, event.target.value, this.state)
            this.setState({ [dataType]: event.target.value })
          }
          // this.setState({ type: event.target.value })
        }
        // 表单提交回调
        submit = (e) => {
          e.preventDefault()
          let { password, username } = this.state
          console.log(password, username)
        }
      }
      // 2、渲染组件到页面
      // ReactDOM.render(组件,容器)
      ReactDOM.render(<Login />, document.getElementById('test'))
    </script>
  </body>
</html>

3、函数柯里化

通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式

上一段代码中的 saveFormData 函数 就是一个函数柯里化

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>演示柯里化</title>
  </head>
  <body>
    <script type="text/javascript">
      function sum(a) {
        return (b) => {
          return (c) => {
            return a + b + c
          }
        }
      }
      console.log(sum(1)(12)(3))
    </script>
  </body>
</html>

4、不用柯里化的写法

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>不用函数柯里化的实现</title>
  </head>
  <body>
    <div id="test"></div>
    <!-- 引入 react 核心库 -->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- 引入 react-dom,用于支持 react 操作DOM -->
    <script
      type="text/javascript"
      src="../js/react-dom.development.js"
    ></script>
    <!-- 引入babel, 用于将 jsx 转为 js -->
    <script type="text/javascript" src="../js/babel.min.js"></script>

    <!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <!-- 此处一定要写babel -->
    <script type="text/babel">
      // 1、创建组件
      class Login extends React.Component {
        // 初始化状态
        state = {
          username: '',
          password: '',
        }
        render() {
          return (
            <form action="xxx" onSubmit={this.submit}>
              用户名:
              <input
                type="text"
                onChange={(event) => {
                  this.saveFormData('username', event)
                }}
                placeholder="用户名"
                name="username"
              />
              <br />
              密码:
              <input
                type="password"
                onChange={(event) => {
                  this.saveFormData('password', event)
                }}
                placeholder="密码"
                name="password"
              />
              <button>登录</button>
            </form>
          )
        }
        // 保存表单数据到状态中
        saveFormData = (dataType, event) => {
          this.setState({ [dataType]: event.target.value })
        }
        // 表单提交回调
        submit = (e) => {
          e.preventDefault()
          let { password, username } = this.state
          console.log(password, username)
        }
      }
      // 2、渲染组件到页面
      // ReactDOM.render(组件,容器)
      ReactDOM.render(<Login />, document.getElementById('test'))
    </script>
  </body>
</html>

三、组件的生命周期

1、例子--引出生命周期

需求:自定义组件实现以下功能

1)让指定的文本做显示/隐藏 的渐变动画

2)从完全可见,到彻底消失,耗时 2s

3)点击 按钮 从界面卸载组件

挂载 mount

卸载 unMount

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>引出生命周期</title>
  </head>
  <body>
    <div id="test"></div>
    <!-- 引入 react 核心库 -->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- 引入 react-dom,用于支持 react 操作DOM -->
    <script
      type="text/javascript"
      src="../js/react-dom.development.js"
    ></script>
    <!-- 引入babel, 用于将 jsx 转为 js -->
    <script type="text/javascript" src="../js/babel.min.js"></script>

    <!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <!-- 此处一定要写babel -->
    <script type="text/babel">
      // 1、创建组件
      // 生命周期回调函数《==》生命周期钩子函数《==》生命周期函数《==》生命周期钩子
      class Life extends React.Component {
        // 初始化状态
        state = {
          opacity: 1,
        }
        // render 调用的时机: 初始化渲染、状态更新之后
        render() {
          console.log('render')
          return (
            <div>
              <h2 style={{ opacity: this.state.opacity }}>
                React 学不会,咋可能啊
              </h2>
              <button onClick={this.deadHandle}>直接噶</button>
            </div>
          )
        }
        // componentDidMount 组件挂载完毕时调用
        componentDidMount() {
          console.log('componentDidMount')
          this.timer = setInterval(() => {
            let { opacity } = this.state
            opacity -= 0.1
            if (opacity <= 0) {
              opacity = 1
            }
            // console.log(opacity)
            this.setState({ opacity })
          }, 200)
        }
        // 组件将要卸载的时候调用
        componentWillUnmount() {
          // 清除定时器
          clearInterval(this.timer)
        }

        deadHandle = () => {
          // // 清除定时器
          // clearInterval(this.timer)
          // 卸载组件
          ReactDOM.unmountComponentAtNode(document.getElementById('test'))
          console.log('按钮点击,将组件直接卸载')
        }
      }
      // 2、渲染组件到页面
      // ReactDOM.render(组件,容器)
      ReactDOM.render(<Life />, document.getElementById('test'))
    </script>
  </body>
</html>

2、理解

1)组件对象从创建到死亡它会经历特定阶段

2)React 组件对象包含一系列钩子函数(生命周期回调函数),在特定的时刻调用

3)我们在定义组件时候,在特定的生命周期回调函数中做特定的工作

3、生命周期(旧)

react v16.8.0

3.1 挂载时(初始化)的流程

执行顺序:

Count---constructor

Count---componentWillMount

Count---render

Count---componentDidMount

卸载组件按钮点击后执行:

Count---componentWillUnmount

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="test"></div>
    <!-- 引入 react 核心库 -->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- 引入 react-dom,用于支持 react 操作DOM -->
    <script
      type="text/javascript"
      src="../js/react-dom.development.js"
    ></script>
    <!-- 引入babel, 用于将 jsx 转为 js -->
    <script type="text/javascript" src="../js/babel.min.js"></script>

    <!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <!-- 此处一定要写babel -->
    <script type="text/babel">
      class Count extends React.Component {
        constructor(props) {
          console.log('Count---constructor')
          super(props)
          this.state = {
            num: 0,
          }
        }
        addHandle = () => {
          let { num } = this.state
          this.setState({ num: num + 1 })
        }
        death = () => {
          ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }
        // 组件将要挂载的钩子
        componentWillMount() {
          console.log('Count---componentWillMount')
        }
        // 组件挂载完毕的钩子
        componentDidMount() {
          console.log('Count---componentDidMount')
        }
        // 组件卸载时的钩子
        componentWillUnmount() {
          console.log('Count---componentWillUnmount')
        }
        render() {
          console.log('Count---render')
          let { num } = this.state
          return (
            <div>
              <h1>当前求和为 {num}</h1>
              <button onClick={this.addHandle}>点我+1</button>
              <button onClick={this.death}>卸载组件</button>
            </div>
          )
        }
      }
      ReactDOM.render(<Count />, document.getElementById('test'))
    </script>
  </body>
</html>
3.2 更新时的流程
3.2.1 流程线路 2(setState 流程)

正常更新:修改状态中的数据 组件能够更新

执行顺序

Count---shouldComponentUpdate

Count---componentWillUpdate

Count---render

Count---componentDidUpdate

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="test"></div>
    <!-- 引入 react 核心库 -->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- 引入 react-dom,用于支持 react 操作DOM -->
    <script
      type="text/javascript"
      src="../js/react-dom.development.js"
    ></script>
    <!-- 引入babel, 用于将 jsx 转为 js -->
    <script type="text/javascript" src="../js/babel.min.js"></script>

    <!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <!-- 此处一定要写babel -->
    <script type="text/babel">
      class Count extends React.Component {
        constructor(props) {
          console.log('Count---constructor')
          super(props)
          this.state = {
            num: 0,
          }
        }
        addHandle = () => {
          let { num } = this.state
          this.setState({ num: num + 1 })
        }
        death = () => {
          ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }
        // 组件将要挂载的钩子
        componentWillMount() {
          console.log('Count---componentWillMount')
        }
        // 组件挂载完毕的钩子
        componentDidMount() {
          console.log('Count---componentDidMount')
        }
        // 组件卸载时的钩子
        componentWillUnmount() {
          console.log('Count---componentWillUnmount')
        }
        // 控制组件更新的"阀门", 需要写一个返回值(类型为 boolean),返回false就不再更新
        shouldComponentUpdate() {
          console.log('Count---shouldComponentUpdate')
          return true
        }
        // 组件将要更新的钩子
        componentWillUpdate() {
          console.log('Count---componentWillUpdate')
        }
        // 组件更新完毕的钩子
        componentDidUpdate() {
          console.log('Count---componentDidUpdate')
        }
        render() {
          console.log('Count---render')
          let { num } = this.state
          return (
            <div>
              <h1>当前求和为 {num}</h1>
              <button onClick={this.addHandle}>点我+1</button>
              <button onClick={this.death}>卸载组件</button>
            </div>
          )
        }
      }
      ReactDOM.render(<Count />, document.getElementById('test'))
    </script>
  </body>
</html>
3.2.2 流程线路 3 (forceUpdate 流程)

强制更新: 不修改状态中的数据但是想要更新页面就会用到。 阀门关闭也不会影响

执行顺序:

Count---componentWillUpdate

Count---render

Count---componentDidUpdate

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="test"></div>
    <!-- 引入 react 核心库 -->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- 引入 react-dom,用于支持 react 操作DOM -->
    <script
      type="text/javascript"
      src="../js/react-dom.development.js"
    ></script>
    <!-- 引入babel, 用于将 jsx 转为 js -->
    <script type="text/javascript" src="../js/babel.min.js"></script>

    <!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <!-- 此处一定要写babel -->
    <script type="text/babel">
      class Count extends React.Component {
        constructor(props) {
          console.log('Count---constructor')
          super(props)
          this.state = {
            num: 0,
          }
        }
        addHandle = () => {
          let { num } = this.state
          this.setState({ num: num + 1 })
        }
        // 卸载组件按钮的回调
        death = () => {
          ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }
        // 强制更新按钮的回调
        force = () => {
          this.forceUpdate()
        }
        // 组件将要挂载的钩子
        componentWillMount() {
          console.log('Count---componentWillMount')
        }
        // 组件挂载完毕的钩子
        componentDidMount() {
          console.log('Count---componentDidMount')
        }
        // 组件卸载时的钩子
        componentWillUnmount() {
          console.log('Count---componentWillUnmount')
        }
        // 控制组件更新的"阀门", 需要写一个返回值(类型为 boolean),返回false就不再更新
        shouldComponentUpdate() {
          console.log('Count---shouldComponentUpdate')
          return true
        }
        // 组件将要更新的钩子
        componentWillUpdate() {
          console.log('Count---componentWillUpdate')
        }
        // 组件更新完毕的钩子
        componentDidUpdate() {
          console.log('Count---componentDidUpdate')
        }
        render() {
          console.log('Count---render')
          let { num } = this.state
          return (
            <div>
              <h1>当前求和为 {num}</h1>
              <button onClick={this.addHandle}>点我+1</button>
              <button onClick={this.death}>卸载组件</button>
              <button onClick={this.force}>
                不更改任何状态的数据,强制更新一下
              </button>
            </div>
          )
        }
      }
      ReactDOM.render(<Count />, document.getElementById('test'))
    </script>
  </body>
</html>
3.2.3 流程线路 1 (父组件 render 流程)

执行顺序:

Child---render

Child---componentWillReceiveProps {carName: '奥迪'}

Child---shouldComponentUpdate

Child---componentWillUpdate

Child---render

Child---componentDidUpdate

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="test"></div>
    <!-- 引入 react 核心库 -->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- 引入 react-dom,用于支持 react 操作DOM -->
    <script
      type="text/javascript"
      src="../js/react-dom.development.js"
    ></script>
    <!-- 引入babel, 用于将 jsx 转为 js -->
    <script type="text/javascript" src="../js/babel.min.js"></script>

    <!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <!-- 此处一定要写babel -->
    <script type="text/babel">
      class Parent extends React.Component {
        // 初始化状态
        state = {
          carName: '奔驰',
        }
        changeCar = () => {
          this.setState({ carName: '奥迪' })
        }

        render() {
          let { carName } = this.state
          return (
            <div>
              Parent, 我是父组件
              <button onClick={this.changeCar}>换车</button>
              <Child carName={carName} />
            </div>
          )
        }
      }
      class Child extends React.Component {
        // 组件将要接收新的prps 的钩子第一次传的不算, 之后的就能够执行,还能够接收到props参数
        componentWillReceiveProps(props) {
          console.log('Child---componentWillReceiveProps', props)
        }
        // 控制组件更新的"阀门", 需要写一个返回值(类型为 boolean),返回false就不再更新
        shouldComponentUpdate() {
          console.log('Child---shouldComponentUpdate')
          return true
        }
        // 组件将要更新的钩子
        componentWillUpdate() {
          console.log('Child---componentWillUpdate')
        }
        // 组件更新完毕的钩子
        componentDidUpdate() {
          console.log('Child---componentDidUpdate')
        }
        render() {
          console.log('Child---render')
          return <div>Child, 我是子组件,接收到的车是{this.props.carName}</div>
        }
      }

      ReactDOM.render(<Parent />, document.getElementById('test'))
    </script>
  </body>
</html>
3.3 总结生命周期(旧)

生命周期的三个阶段

**1、初始化阶段:**由 ReactDom.render() 触发---初次渲染

constructor()

componentWillMount()

render()

componentDidMount() ====》常用,一般再这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息

**2、更新阶段:**由组件内部 this.setState() 或父组件重新 render 触发

shouldComponentUpdate()

componentWillUpdate()

render() =======>必须

componentDidUpdate()

**3、卸载组件:**由 ReactDOM.unmountComponentAtNode() 触发

componentWillUnmount() ====》常用,一般再这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

4、对比新旧生命周期

新的生命周期即将不再维护componentWillMount、componentWillUpdate、

新增 getDerivedStateFromProps、getSnapshotBeforeUpdate,但是不是替代之前前面丢弃的钩子,这两个新的钩子基本不用

React v18.3.0

4.1 重要的钩子

render:初始化渲染或更新渲染调用

ComponentDidMount:开启监听,发送 ajax请求

componentWillUnmount:做一些收尾工作,如:清理定时器

4.2 即将废弃的钩子

omponentWillMount

componentWillUpdate

componentWillUnmount

4.3 getSnapshotBeforeUpdate的使用场景
html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>生命周期(新)</title>
    <style>
    .list {
      width: 200px;
      height: 150px;
      background-color: skyblue;
      overflow-y: auto;
  }
  .news {
      height: 30px;
  }
</style>
  </head>
  <body>
    <div id="test"></div>
    <!-- 引入 react 核心库 -->
    <script type="text/javascript" src="../js/v18.3.0/react.development.js"></script>
    <!-- 引入 react-dom,用于支持 react 操作DOM -->
    <script
      type="text/javascript"
      src="../js/v18.3.0/react-dom.development.js"
    ></script>
    <!-- 引入babel, 用于将 jsx 转为 js -->
    <script type="text/javascript" src="../js/v18.3.0/babel.min.js"></script>

    <!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
    <script type="text/javascript" src="../js/v18.3.0/prop-types.js"></script>

    <!-- 此处一定要写babel -->
    <script type="text/babel">
      class NewsList extends React.Component {
        state = {
          newArr:[]
        }
        componentDidMount(){
          this.timer = setInterval(()=>{
            const {newArr} = this.state
            let news = '新闻'+(newArr.length+1)
            this.setState({
              newArr: [news, ...newArr]
            })
          },1000)
        }
        // 在更新之前获取快照
        getSnapshotBeforeUpdate(){
          console.log("getSnapshotBeforeUpdate", this.refs.list.scrollHeight)
          return this.refs.list.scrollHeigh
        }
        componentDidUpdate(prePops, preState, height){
          this.refs.list.scrollTop += this.refs.list.scrollHeight-height
        }
        render() {
          console.log('Count---render')
          return (
            <div className="list" ref='list'>
              {this.state.newArr.map((el,inx)=>{
                return <div className="news" key={inx}>{el}</div>
              })}
              
          </div>
          )
        }
      }
      ReactDOM.render(<NewsList />, document.getElementById('test'))
    </script>
  </body>
</html>
4.3 总结新的生命周期(常用的 render、ComponentDidMount、componentWillUnmount 是没有更改的)

**1、初始化阶段:**由 ReactDom.render() 触发---初次渲染

constructor()

getDerivedStateFromProps()

render()

componentDidMount() ====》常用,一般再这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息

**2、更新阶段:**由组件内部 this.setState() 或父组件重新 render 触发

getDerivedStateFromProps

shouldComponentUpdate()

render() =======>必须

getSnapshotBeforeUpdate()

componentDidUpdate()

**3、卸载组件:**由 ReactDOM.unmountComponentAtNode() 触发

componentWillUnmount() ====》常用,一般再这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

相关推荐
Boilermaker199219 分钟前
【Java EE】SpringIoC
前端·数据库·spring
中微子30 分钟前
JavaScript 防抖与节流:从原理到实践的完整指南
前端·javascript
天天向上10241 小时前
Vue 配置打包后可编辑的变量
前端·javascript·vue.js
芬兰y1 小时前
VUE 带有搜索功能的穿梭框(简单demo)
前端·javascript·vue.js
好果不榨汁1 小时前
qiankun 路由选择不同模式如何书写不同的配置
前端·vue.js
小蜜蜂dry1 小时前
Fetch 笔记
前端·javascript
拾光拾趣录1 小时前
列表分页中的快速翻页竞态问题
前端·javascript
小old弟1 小时前
vue3,你看setup设计详解,也是个人才
前端
Lefan1 小时前
一文了解什么是Dart
前端·flutter·dart
Patrick_Wilson1 小时前
青苔漫染待客迟
前端·设计模式·架构