React 面向组件编程(下)

慈云数据 2024-03-12 技术支持 109 0

目录

  • 前言:
  • 一、受控组件与非受控组件
    • 1. 受控组件
    • 2. 非受控组件
    • 3. 效果展示
    • 4. 总结:
    • 二、组件的生命周期
      • 1. 对生命周期的理解
      • 2. 生命周期的三个阶段(旧)
      • 3. 生命周期的三个阶段(新)
      • 4. 新旧生命周期的区别
      • 5. 重要的勾子
      • 6. 即将废弃的勾子
      • 三、高阶函数和函数柯里化的理解
        • 1. 高阶函数
        • 2. 函数的柯里化
        • 3. 使用函数柯里化代码示例
        • 4. 不用函数柯里化代码示例
        • 总结:

          前言:

          在React面向组件编程中,除了上一章节的组件实例的三大核心属性以外,还有很多重要的内容比如:React 的生命周期,受控组件与非受控组件,高阶函数和函数柯里化的理解等,在本文中会给大家继续讲解React 面向组件编程中剩余的内容。


          一、受控组件与非受控组件

          表单的组件分类:

          1. 受控组件
          2. 非受控组件

          多数情况下,推荐使用受控组件实现表单。在受控组件中,表单数据由组件控制。

          另外一种是非受控组件,这种方式下表单组件由DOM自身控制。


          1. 受控组件

          1. 受控组件通过 props 获取其当前值,并通过回调函数(比如 onChange )通知变化
          2. 表单状态发生变化时,都会通知 React,将状态交给 React 进行处理,比如可以使用 useState 存储
          3. 受控组件中,组件渲染出的状态与它的 value 或 checked 属性相对应
          4. 受控组件会更新 state 的流程
          class Login extends React.Component {
              // 初始化状态
              state = {
                  username:'', // 用户名
                  password:'', // 密码
              }
              // 保存用户名到状态中
              saveUsername=(event)=>{
                  this.setState({username:event.target.value})
              }
              // 保存密码到状态中
              savePassword=(event)=>{
                  this.setState({password:event.target.value})
              }
              // 表单提交的回调
              handleSubmit=(event)=>{
                  event.preventDefault(); // 阻止默认事件
                  
                  let {username,password} = this.state
                  alert(`你输入的用户名是${username},密码是${password}`)
              }
              render(){
                  return(
                      
          this.handleSubmit} 用户名:this.saveUsername} name="username" / 密码:this.savePassword} name="password" / 登录
          ) } }

          2. 非受控组件

          非受控组件将数据存储在 DOM 中,而不是组件内,这比较类似于传统的 HTML 表单元素。

          1. 非受控组件的值不受组件自身的 state 和 props 控制
          2. 非受控组件使用 ref 从 DOM 中获取元素数据
          class Login extends React.Component {
              handleSubmit=(event)=>{
                  // console.log(e>=event)
                  event.preventDefault(); // 阻止默认事件
                  
                  let {username,password} = this
                  alert(`你输入的用户名是${username.value},密码是${password.value}`)
              }
              render(){
                  return(
                      
          this.handleSubmit} 用户名:c=this.username = c} name="username" /> 密码:c=this.password = c} name="password" /> 登录
          ) } }

          3. 效果展示

          在这里插入图片描述


          4. 总结:

          1. React 中的组件分为受控组件和非受控组件
          2. 受控组件的两个要点:
            • 组件的 value 属性与 React 中的状态绑定
            • 组件内声明了 onChange 事件处理 value 的变化
            • 非受控组件更像是传统的 HTML 表单元素,数据存储在 DOM 中,而不是组件内部,获取数据的方式是通过 ref 引用
            • 一些建议:
              • 尽可能使用受控组件
              • 受控组件是将状态交由 React 处理,可以是任何元素,不局限于表单元素
              • 对于有大量表单元素的页面,使用受控组件会使程序变得繁琐难控,此时使用非受控组件更为明智
              • 在受控组件中,数据流是单向的( state 是变化来源),因此在改变 state 时都应该使用 setState ,而不要强制赋值
              • Refs 不能用于函数式组件,因为函数式组件没有实例
              • 在函数式组件内部,是可以使用 Refs 的

          二、组件的生命周期

          所谓的React生命周期,就是指组件从被创建出来,到被使用,最后被销毁的这么一个过程;

          而在这个过程中,React提供了我们会自动执行的不同的钩子函数,我们称之为生命周期函数;

          组件的生命周期大致分为三个阶段:组件挂载阶段,组件更新阶段,组件销毁卸载阶段

          react在版本16.3前后存在两套生命周期,16.3之前为旧版,之后则是新版,虽有新旧之分,但主体上大同小异。


          1. 对生命周期的理解

          1. 组件从创建到死亡它会经历一些特定的阶段。
          2. React组件中包含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用。
          3. 我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作。

          2. 生命周期的三个阶段(旧)

          在这里插入图片描述

          1. 初始化阶段: 由ReactDOM.render()触发—初次渲染
            1. constructor()
            2. componentWillMount()
            3. render()
            4. componentDidMount()
          2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
            1. shouldComponentUpdate()
            2. componentWillUpdate()
            3. render()
            4. componentDidUpdate()
          3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
            1. componentWillUnmount()
          
          
              
              
              
              生命周期旧
          
          
              
              
          class Count extends React.Component { state = { count:0 } add = ()=>{ // 获取原状态 let {count} = this.state // 更新状态 this.setState({count:count+1}) } death = ()=>{ ReactDOM.unmountComponentAtNode(document.getElementById('test')) } force = ()=>{ this.forceUpdate() // 强制更新 } // 数据更新的 ‘阀门~’ shouldComponentUpdate() { console.log("Count --- shouldComponentUpdate"); return true // 这里必须有返回4值,其次返回值默认是true } // 组件将要更新的钩子 componentWillUpdate() { console.log("Count ---- componentWillUpdate"); } // 组件更新完成的钩子 componentDidUpdate() { console.log("Count ---- componentDidUpdate"); } render(){ console.log("render"); let {count} = this.state return(

          当前求和为:{count}

          this.add}点我+1 this.death}卸载组件 this.force}不更改任何状态中的数据,强制更新
          ) } } // 父组件 class A extends React.Component { state = {carName:'小三轮'} changeCar = ()=>{ this.setState({carName:"宾利"}) } render(){ console.log('A ---- render'); return(
          我是A组件
          this.changeCar}换车 this.state.carName}
          ) } } // 子组件 class B extends A { // 组件将要接收新的props的钩子 componentWillReceiveProps(){ console.log('B ---- componentWillReceiveProps'); } // 数据更新的 ‘阀门~’ shouldComponentUpdate() { console.log("B --- shouldComponentUpdate"); return true // 这里必须有返回4值,其次返回值默认是true } // 组件将要更新的钩子 componentWillUpdate() { console.log("B ---- componentWillUpdate"); } // 组件更新完成的钩子 componentDidUpdate() { console.log("B ---- componentDidUpdate"); } render(){ console.log('B ---- render'); return(
          我是B组件,接收到的车是:{this.props.carName}
          ) } } ReactDOM.render(,document.getElementById('test'))

          3. 生命周期的三个阶段(新)

          在这里插入图片描述

          1. 初始化阶段: 由ReactDOM.render()触发—初次渲染
            1. constructor()
            2. getDerivedStateFromProps
            3. render()
            4. componentDidMount()
          2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
            1. getDerivedStateFromProps
            2. shouldComponentUpdate()
            3. render()
            4. getSnapshotBeforeUpdate
            5. componentDidUpdate()
          3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
            1. componentWillUnmount()
          
          
              
              
              
              生命周期新
          
          
              
              
          class Count extends React.Component { state = { count:0 } add = ()=>{ // 获取原状态 let {count} = this.state // 更新状态 this.setState({count:count+1}) } death = ()=>{ ReactDOM.unmountComponentAtNode(document.getElementById('test')) } force = ()=>{ this.forceUpdate() // 强制更新 } // 数据更新的 ‘阀门~’ shouldComponentUpdate() { console.log("Count --- shouldComponentUpdate"); return true // 这里必须有返回4值,其次返回值默认是true } // 组件将要更新的钩子 componentWillUpdate() { console.log("Count ---- componentWillUpdate"); } // 组件更新完成的钩子 componentDidUpdate() { console.log("Count ---- componentDidUpdate"); } render(){ console.log("render"); let {count} = this.state return(

          当前求和为:{count}

          this.add}点我+1 this.death}卸载组件 this.force}不更改任何状态中的数据,强制更新
          ) } } // 父组件 class A extends React.Component { state = {carName:'小三轮'} constructor(props) { state } changeCar = ()=>{ this.setState({carName:"宾利"}) } static getDerivedStateFromProps(props, state) { // 这里必须要一个返回值 ==> state or null // 这里的state会覆盖掉原本的状态,并且后续也无法修改 // 能将外部的接收的props 赋值给组件自身的 state // 如果你希望自身的state一直,全部依赖于外部的props,那么可以使用这个生命周期函数 return {carName:"QQ"} } // 获取护具更新前的快照,能拿到旧的props和state // 必须有返回值 getSnapshotBeforeUpdate = (prevProps, prevState) => { } render(){ console.log('A ---- render'); return(
          我是A组件
          this.changeCar}换车 this.state.carName}
          ) } } // 子组件 class B extends A { // 组件将要接收新的props的钩子 UNSAFE_componentWillReceiveProps(){ console.log('B ---- componentWillReceiveProps'); } // 数据更新的 ‘阀门~’ shouldComponentUpdate() { console.log("B --- shouldComponentUpdate"); return true // 这里必须有返回4值,其次返回值默认是true } // 将要挂载时 UNSAFE_componentWillMount() { console.log("Count --- componentWillUnMount"); } // 组件将要更新的钩子 UNSAFE_componentWillUpdate() { console.log("B ---- componentWillUpdate"); } // 组件更新完成的钩子 componentDidUpdate() { console.log("B ---- componentDidUpdate"); } render(){ console.log('B ---- render'); return(
          我是B组件,接收到的车是:{this.props.carName}
          ) } } ReactDOM.render(,document.getElementById('test'))

          4. 新旧生命周期的区别

          1. 新生命周期中去掉了三个 will 钩子,分别为 componentWillMount、componentWillReceiveProps、componentWillUpdate;
          2. 新生命周期中新增了两个钩子,分别为 getDerivedStateFromProps(从 props 中得到衍生的 state )和 getSnapshotBeforeUpdate。

          5. 重要的勾子

          1. render:初始化渲染或更新渲染调用
          2. componentDidMount:开启监听, 发送ajax请求
          3. componentWillUnmount:做一些收尾工作, 如: 清理定时器

          6. 即将废弃的勾子

          1. componentWillMount
          2. componentWillReceiveProps
          3. componentWillUpdate

          警告:

          现在使用会出现警告,下一个大版本需要加上 UNSAFE_ 前缀才能使用,以后可能会被彻底废弃,不建议使用。


          三、高阶函数和函数柯里化的理解

          1. 高阶函数

          如果一个函数符合下面2个规范中的任何一个,那么它就属于一个高阶函数

          1. 若A函数,接收的参数是一个函数,那么A就可以称为高阶函数
          2. 若A函数,它的返回值依然是一个函数,那么A就可以称为高阶函数

          常见的高阶函数:Promise,setTimeout,arr.map(数组方法)


          2. 函数的柯里化

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

          function sum(a){
              return (b)=>{
                  return (c)=>{
                      return a + b + c
                  }
              }
          }
          const result = sum(1)(2)(3)
          console.log(result);
          

          3. 使用函数柯里化代码示例

          class Login extends React.Component {
              // 初始化状态
              state = {
                  username:'', // 用户名
                  password:'', // 密码
              }
              // 保存表单数据到状态中
              saveFormDate=(dataType,event)=>{ // 标识当前标签
                  this.setState({[dataType]:event.target.value})
              }
              // 表单提交的回调
              handleSubmit=(event)=>{
                  event.preventDefault(); // 阻止默认事件
                  
                  let {username,password} = this.state
                  alert(`你输入的用户名是${username},密码是${password}`)
              }
              render(){
                  return(
                      
          this.handleSubmit} 用户名:(event)=this.saveFormDate('username',event)} name="username" /> 密码:(event)=this.saveFormDate('password',event)} name="password" /> 登录
          ) } }

          4. 不用函数柯里化代码示例

          class Login extends React.Component {
              // 初始化状态
              state = {
                  username:'', // 用户名
                  password:'', // 密码
              }
              // 保存表单数据到状态中
              saveFormDate=(dataType)=>{ // 标识当前标签
                  return (event)=>{ // 这里的回调谁执行? input标签的 onChange事件
                      this.setState({[dataType]:event.target.value})
                  }
              }
              // 表单提交的回调
              handleSubmit=(event)=>{
                  event.preventDefault(); // 阻止默认事件
                  
                  let {username,password} = this.state
                  alert(`你输入的用户名是${username},密码是${password}`)
              }
              render(){
                  return(
                      
          this.handleSubmit} 用户名:this.saveFormDate('username')} name="username" / 密码:this.saveFormDate('password')} name="password" / 登录
          ) } }

          总结:

          欢迎大家加入我的社区,在社区中会不定时发布一些精选内容:https://bbs.csdn.net/forums/db95ba6b828b43ababd4ee5e41e8d251?category=10003


          以上就是 React 面向组件编程(下),不懂得也可以在评论区里问我或私聊我询问,以后会持续发布一些新的功能,敬请关注。

          我的其他文章:https://blog.csdn.net/weixin_62897746?type=blog

微信扫一扫加客服

微信扫一扫加客服

点击启动AI问答
Draggable Icon