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() ====》常用,一般再这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

相关推荐
一个处女座的程序猿O(∩_∩)O1 小时前
小型 Vue 项目,该不该用 Pinia 、Vuex呢?
前端·javascript·vue.js
hackeroink4 小时前
【2024版】最新推荐好用的XSS漏洞扫描利用工具_xss扫描工具
前端·xss
迷雾漫步者6 小时前
Flutter组件————FloatingActionButton
前端·flutter·dart
向前看-6 小时前
验证码机制
前端·后端
燃先生._.7 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖8 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
m0_748235248 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_748240259 小时前
前端如何检测用户登录状态是否过期
前端
black^sugar9 小时前
纯前端实现更新检测
开发语言·前端·javascript