React学习笔记(三)

149 阅读6分钟

一.React事件处理

  • React的事件是通过onXxx属性指定事件处理函数 ----为了更好的兼容性

    • React使用的都是自定义(合成)事件,而不是原生的事件 ----为了的高效
    • React中的事件是通过事件委托方式处理的
  • 事件中必须返回的是函数

  • 通过event.target得到发生事件的DOM元素对象----不要过度使用 ref

发生事件的元素是需要操作的元素时,可以避免使用ref

  //1.创建组件
  class Demo extends React.Component {
    /*
     (1).通过onXxx属性指定事件处理函数(注意大小写)
        a.React使用的是自定义(合成)事件,而不是使用的原生DOM事件 ———— 为了更好的兼容性
        b.React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ———— 为了高效
    (2).通过event.target得到发生事件的DOM元素对象
     */
    myRef = React.createRef()
    myRef2 = React.createRef()
​
    //展示左侧输入框数据
    showData = () => {
      alert(this.myRef.current.value)
      console.log(this.myRef)
    }
​
    //展示右侧输入框数据
    showData2 = () => {
      alert(this.myRef2.current.value)
    }
​
    render() {
      return (
              <div>
                <input ref={this.myRef} type="text" placeholder="点击按钮提示数据"/>
                <button onClick={this.showData}>点我提示输入的数据</button>
                <input onBlur={this.showData2} ref={this.myRef2} type="text"/>
              </div>
      )
    }
  }
​
  //2.渲染组件到页面
  ReactDOM.render(<Demo/>, document.getElementById('test'))

二、收集表单数据

1.理解包含表单的组件分类

  • 受控组件
  • 非受控组件

2.需求:定义一个包含的表单的组件,输入用户名后,密码登陆提示输入信息

1.gif

2.1 非受控组件

页面中所有输入类DOM的值,都是现用现取的

 //1.创建组件
class Login extends React.Component {
    login = (event) =>{
      event.preventDefault(); //阻止表单提交
      alert(`你输入的的用户名:${this.name.value},密码是:${this.pwd.value}`);
  
    }
  
    render() {
      return (
              <form action="http://www.baidu.com" onSubmit={this.login}>
                用户名:<input ref = {c => this.name =c } type = "text" name ="username"/>
                密码<input ref = {c => this.pwd =c } type = "password" name ="password"/>
                <button>登录</button>
              </form>
      )
    }
}
​
//2.渲染组件到页面
ReactDOM.render(<Login/>, document.getElementById('test'))

2.2 受控组件

页面中输入类的DOM,随着输入的过程,将数据存储在状态state中,需要用的时候在从状态state中取(有点类似Vue中的双向数据绑定)

 class Login extends React.Component{
     state = {
         name:"",
         pwd:""
      }
        
        saveName = (event) =>{
            this.setState({name:event.target.value});
        }
​
        savePwd = (event) => {
            this.setState({pwd:event.target.value});
        }
​
        render() {
            return (
                <form action="http://www.baidu.com" onSubmit={this.login}>
                    用户名:<input onChange={this.saveName} type = "text" name ="username"/>
                    密码<input onChange={this.savePwd} type = "password" name ="password"/>
                    <button>登录</button>
                </form>
            )
        }
    }
​
    ReactDOM.render(<Login />,document.getElementById("div"));

三.高阶函数与函数柯里化

3.1 高阶函数

高级函数:如果一个函数符合下面2个规范中的任何一个,那该函数就是高级而函数

  • 若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数。
  • 若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数。

常见的高阶函数有: PromisesetTimeoutarr.map()等等

3.2 函数柯里化

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

function sum1(a, b, c){
  return a + b + c;
}
sum1(1, 2, 3)
​
// 柯里化后
function sum(a){
  return(b)=>{
    return (c)=>{
      return a+b+c
    }
  }
}
sum(1)(2)(3)

3.3 利用 利用高阶函数与函数柯里化简写

class Login extends React.Component{
    state = {
        name:"",
        pwd:""
    }
        
    login = (event) =>{
        event.preventDefault(); //阻止表单提交
        alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
    }
​
        
​
    //保存表单数据到状态中 (高阶函数+函数柯里化)
  saveType = (type) =>{
        return (event) => {
            this.setState({[type]:event.target.value});
        }
    }
​
        //因为事件中必须是一个函数,所以返回的也是一个函数,这样就符合规范了
  render() {
        return (
            <form action="http://www.baidu.com" >
              用户名:<input onChange = {this.saveType('name')} type = "text" name ="username"/>
              {/*直接调用回调函数也是可以的:将数据传递过去就可以*/}
              用户名:<input onChange = {(event)=>{this.saveType('name',event)}} type = "text" name ="username"/>
              密码<input onChange = {this.saveType('pwd')} type = "password" name ="password"/>
              <button>登录</button>
            </form>
        )
    }
}
​
ReactDOM.render(<Login />,document.getElementById("test"));

3.4 不利用柯里化实现

 class Login extends React.Component {
    state = {
        name: "",
        pwd: ""
    };
​
    //保存表单数据到状态中
    saveType = (type) => {
        return (event) => {
          this.setState({[type]: event.target.value});
        }
    }
​
    //提交表单数据到状态中
    login = (event) => {
        event.preventDefault(); //阻止表单提交
        const {name, pwd} = this.state
        alert(`你输入的用户名是:${name},你输入的密码是${pwd}`)
    }
    
    render() {
        return (
            <form action="http://www.baidu.com">
              用户名:<input onChange={this.saveType('name')} type="text" name="username"/>
              {/*直接调用回调函数也是可以的:将数据传递过去就可以*/}
              用户名:<input onChange={event => this.saveType('name', event)} type="text" name="username"/>
              密码<input onChange={this.saveType('pwd')} type="password" name="password"/>
              <button>登录</button>
            </form>
        )
    }
}
​
ReactDOM.render(<Login/>, document.getElementById("test"));

四.组件的生命周期

4.1 理解

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

4.2 引入案例

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

  • 1.让指定的文本做显示 / 隐藏的渐变动画
  • 2.从完全可见,到彻底消失,耗时2S
  • 3.点击“不活了”按钮从界面中卸载组件
    //创建组件
    //生命周期回调函数 <=> 生命周期钩子函数 <=> 生命周期函数 <=> 生命周期钩子
    class Life extends React.Component {
​
        //初始化状态,定义透明度为1
        state = {opacity: 1}
​
        death = () => {
            //卸载组件
            ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }
​
        //组件挂载完毕
        componentDidMount() {
            this.timer = setInterval(()=>{
                //获取原状态
                let {opacity} = this.state
                //减少0.1
                opacity -= 0.1
                if (opacity <= 0) opacity = 1
                //设置新的透明度
                this.setState({opacity})
            },200)
        }
​
        //组件将要卸载
        componentWillUnmount() {
            //清除定时器
            clearInterval(this.timer)
        }
​
        //初始化渲染、状态更新之后
        render() {
            console.log('render')
            return (
                <div>
                    <h2 style={{opacity:this.state.opacity}}>React学不会怎么办?</h2>
                    <button onClick={this.death}>不活了</button>
                </div>
            )
        }
​
    }
    //渲染页面
    ReactDOM.render(<Life/>, document.getElementById("test"));

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

生命周期流程图(旧).png

4.3.1初始化阶段

ReactDOM.render()触发---初次渲染

  • 1.constructor() —— 类组件中的构造函数

  • 2.componentWillMount() —— 组件将要挂载 【即将废弃】

  • 3.render() —— 挂载组件

  • 4.componentDidMount() —— 组件挂载完成 比较常用

    • 一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
class Count extends React.Component{
    // 构造器
    constructor(props){
      alert('constructor')
      console.log('Count---constructor');
      super(props)
      //初始化状态
      this.state = {count:0}
    }
    add = () => {
      const {count} = this.state
      this.setState({count: count+1})
    }
    
    //组件将要挂载的钩子
    componentWillMount(){
      alert('componentWillMount')
      console.log('Count---componentWillMount');
    }
  
    render(){
      alert('render')
      console.log('Count---render');
      const {count} = this.state
      return(
        <div>
          <h1>当前计数值:{count}</h1>
          <button onClick={this.add}>点我+1</button>
        </div>
      )
    }
  
    //组件挂载完毕的钩子
    componentDidMount(){
      alert('componentDidMount')
      console.log('Count---componentDidMount');
    }
  }
  ReactDOM.render(<Count/>, document.getElementById('test'))

4.3.2更新阶段

【第一种情况】父组件重新render触发

  • 1.componentWillReceiveProps() —— 接收属性参数(非首次)【即将废弃】

然后调用下面的钩子函数

【第二种情况】由组件内部this.setSate()

  • 1.shouldComponentUpdate()—— 组件是否应该被更新(默认返回true

然后调用下面的钩子函数

【第三种情况】强制更新 forceUpdate()

  • 2.componentWillUpdate() ——组件将要更新 【即将废弃】
  • 3.render() —— 组件更新
  • 4.componentDidUpdate() —— 组件完成更新

4.3.3卸载组件

ReactDOM.unmountComponentAtNode()触发

  • 1.componentWillUnmount() —— 组件即将卸载

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

生命周期流程图(新).png

4.4.1 初始化阶段

ReactDOM.render()触发 —— 初次渲染

    1. constructor() —— 类组件中的构造函数
  • 2.static getDerivedStateFromProps(props, state) 从props得到一个派生的状态【新增】
  • 3.render() —— 挂载组件
  • 4.componentDidMount() —— 组件挂载完成 比较==常用==

4.4.2 更新阶段

由组件内部this.setSate()或父组件重新render触发或强制更新forceUpdate()

  • 1.getDerivedStateFromProps() —— 从props得到一个派生的状态 【新增】
  • 2.shouldComponentUpdate()—— 组件是否应该被更新(默认返回true)
  • 3.render() —— 挂载组件
  • 4.getSnapshotBeforeUpdate() —— 在更新之前获取快照【新增】
  • 4componentDidUpdate(prevProps, prevState, snapshotValue) —— 组件完成更新

4.4.3 卸载组件

由ReactDOM.unmountComponentAtNode()触发

  • 1.componentWillUnmount() —— 组件即将卸载

4.4.3 重要的勾子

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

4.4.4 即将废弃的勾子

  • 1.componentWillMount
  • 2.componentWillReceiveProps
  • 3.componentWillUpdate

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

五.参考

React官网:react.docschina.org

尚硅谷视频:www.bilibili.com/video/BV1wy…