React学习02 -事件处理、生命周期和diffing算法

文章目录

  • react事件处理
      • 非受控组件
      • 受控组件
      • 高阶函数
      • 函数柯里化
  • 生命周期
      • 引出生命周期
      • 旧版生命周期
      • 新版生命周期
  • Diffing算法

react事件处理

1.react通过onXXX属性指定事件处理函数,
a.react使用的是自定义事件,将原生js事件方法重写并改为小驼峰写法,为了更好的兼容性
b.react中的事件是通过事件委托的方式处理的,在给各个标签添加事件时,其实都是加给最外层标签上;

// 原生js使用事件冒泡,将子标签的事件挂在最外层标签上
<ul id="list">
  <li>item1</li>
  <li>item2</li>
  <li>item3</li>
</ul>
const list = document.getElementById('list');
list.addEventListener('click', (event)=>{
  if(event.target.tagName === 'LI'){  //通过event.target获取标签元素
    console.log(event.target.textContent);  // 打印点击的元素内容
  }
})

2.react通过event.target得到发生事件的DOM元素对象,不要过度使用ref,当发生事件的元素正好的要操作的元素时,可以不使用ref,达到ref的效果。
在调用方法的时候,传递一个event参数,event.target表示的就是当前元素。

class Demo extends React.Component{
  showData = (event)=>{
    console.log(event.target); // <input type="text" />
    console.log(event.target.value); // 输入框的输入的值
  }
  render(){
    return (
      <input onBlur={this.showData} type="text" />
    )
  }
}

非受控组件

拥有输入性标签,比如输入框、单选框、多选框等元素的组件,且标签的值现取现用(比如下面例子中,输入的用户名与密码点击登录需要使用),这样的组件叫做非受控组件。

// 非受控组件示例
class Login extends React.Component{
  login = ()=>{
    event.preventDefault(); // 阻止表单提交
    console.log(this.username.value, this.password.value);
  }
  render(){
    return (
      <form onSubmit={this.login}>
         <input ref={(a)=>{this.username=a}} type="text" name="username" />
         <input ref={(a)=>{this.password=a}} type="password" name="password" />
         <button>登录</button>
      </form>
    )
  } // 点击登录后显示用户名与密码,表单提交后默认会跳转页面,所以利用原生事件阻止跳转
}

受控组件

拥有输入性标签,可以将标签的值存储到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)
  }

  login = ()=>{
    event.preventDefault(); // 阻止表单提交
    console.log(this.state.username, this.state.password);
  }
  render(){
    return (
      <form onSubmit={this.login}>
         <input onChange={this.saveUsername} type="text" name="username" />
         <input onChange={this.savePassword} type="password" name="password" />
         <button>登录</button>
      </form>
    )
  }  // 使用onCahnge方法,随着标签的值变化,做到state也变化,进而页面也变化,类似vue的双向绑定。
}

建议使用受控组件,可以减少ref的使用。

高阶函数

符合下面两个规范中的任一个的函数,叫做高阶函数。
1.函数接收的参数是一个函数
2.函数返回的是一个函数
常见的高阶函数:Promise, setTimeout, arr.map()得等

// 对象相关的知识,把变量的值作为对象属性的key,要使用[]
let a = 'name';
lei obj = {};
obj.a = 'tom';
console.log(obj); // {a:tom}
obj[a] = 'tom';
console.log(obj); // {a:tom, name:tom}
// 实现只使用一个方法,获取不同的元素值,并存储到state中
class Login extends React.Component{
  // 初始化状态
  state = {
    username='',
    password=''
  }
  
  saveFormData = (key)=>{
    console.log(key);
    return (event)=>{
      console.log(event.target.value);
      // this.setState({key:event.target.value}); //这样会给state添加一个属性,{key:输入的值,username='',password=''}
      this.setState({[key]:event.target.value}); // state={username=输入的值,password=输入的值}
    } // return的这个函数才是onChange真正的回调
  }

  login = ()=>{
    event.preventDefault(); // 阻止表单提交
    console.log(this.state.username, this.state.password);
  }
  render(){
    return (
      <form onSubmit={this.login}>
         <input onChange={this.saveFormData('username')} type="text" name="username" />
         <input onChange={this.saveFormData('password')} type="password" name="password" />
         <button>登录</button>
      </form>
    )
  }  // 使用onCahnge方法,{}内应该有一个函数作为onChang方法的回调,加了(),在初始化页面的时候就会调用一次saveFormData方法,默认返回undefined,导致onChange方法失效,所以saveFormData需要返回一个函数,才能保持onChange方法的作用
}

函数柯里化

函数里返回函数,外层函数的参数接收,在最内层函数实现统一处理

// 举例,使用函数柯里化实现三数之和
function sum(a){
  return (b)=>{
    return (c)=>{
      return a+b+c
    }
  }
}
sum(1)(2)(3)  //6
// 比如上面例子中的saveFormData,外层函数接收key,返回的函数接收event,最后在返回的函数中使用key和event处理数据
saveFormData = (key)=>{
    return (event)=>{
      console.log(event.target.value);
      this.setState({[key]:event.target.value});
    } 
}

不使用函数柯里化实现onChange传参

class Login extends React.Component{
  state = {
    username='',
    password=''
  }
  
  saveFormData = (key,event)=>{
      this.setState({[key]:event.target.value}); 
    } 
  

  login = ()=>{
    event.preventDefault(); // 阻止表单提交
    console.log(this.state.username, this.state.password);
  }
  render(){
    return (
      <form onSubmit={this.login}>
         <input onChange={event=>this.saveFormData('username',event)} type="text" name="username" />
         <input onChange={event=>this.saveFormData('password',event)} type="password" name="password" />
         <button>登录</button>
      </form>
    )
  } 
}

生命周期

引出生命周期

概念: 挂载:mount,卸载:unmount
生命周期回调函数(钩子函数):componentDidMount、componentWillUnmount、render…

<div id="test"></div>
class Life ectends React.Component{
  // 移除页面元素
  removeDiv = ()=>{
   // claerInterval(this.timer); // 移除定时器,放在componentWillUnmount方法里等效
    ReactDOM.unmountComponentAtNode(document.getElementById('test')); // 卸载组件
  }
  
  // React在组件挂载完毕时调用
  componentDidMount(){
    // 将定时器挂在组件实例对象上,方便移除组件时可以获取到该定时器
    this.timer = setInterval(()=>{
      let {opacity} = this.state;
      opacity -= 0.1;
      if(opacity<=0) opacity=1;
      this.setState(opacity:opacity);
    },200); // 每0.2秒减少0.1的透明度
  }
  
 // React在组件将要被卸载时调用
 componentWillUnmount(){
   claerInterval(this.timer); // 移除定时器
 }

 // React在初始化渲染、状态更新时调用
  render(){
    return (
      <div>
        <div style={{opacity:this.state.opacity}}>逐渐消失</div>
        <button onClick={this.removeDiv}>点击移除</button>
      </div>
    )
  }
}

旧版生命周期

组件从创建到死亡会经历一些特定阶段,React组件包含一系列钩子函数,会在这些特定阶段调用。钩子函数的调用与定义的顺序无关。

旧版生命周期

图片线路1–挂载渲染页面流程

// 由案例查看各个生命周期钩子--图片左侧路线1相关的钩子
class Count extends React.Component{
  // 构造器
  constructor(props){
    console.log('<Count/> - constructor');
    super(props);
    this.state = {count:0}
  }
  // 组件将要挂载
  componentWillMount(){
    console.log('<Count/> - componentWillMount');
  }
  add = ()=>{
    const count = this.state.count;
    this.setState({count:count+1});
  }
  remove = ()=>{
    ReactDOM.unmounComponentAtNode(document.getElementById('test'));
  }
  // 组件渲染更新
  render(){
    console.log('<Count/> - render');
    return (
      <div>
        <h2>当前求和为:{this.state.count}</h2>
        <button onClick={this.add}>点击+1</button>
        <button onClick={this.remove}>点击卸载组件</button>
      </div>
    )
  }
  // 组件挂载完毕
  componentDidMount(){
    console.log('<Count/> - componentDidMount');
  }
  // 组件将要卸载
  componentWillUnmount(){
    console.log('<Count/> - componentWillUnmount');
  }
}
// 页面加载完成打印顺序constructor->componentWillMount->render->componentDidMount
// 点击卸载组件按钮执行componentWillUnmount钩子

图片线路2–setState流程

class Count extends React.Component{
  state = {count:0}
  add = ()=>{
    const count = this.state.count;
    this.setState({count:count+1});
  }
  remove = ()=>{
    ReactDOM.unmounComponentAtNode(document.getElementById('test'));
  }
  // 组件渲染更新
  render(){
    console.log('<Count/> - render');
    return (
      <div>
        <h2>当前求和为:{this.state.count}</h2>
        <button onClick={this.add}>点击+1</button>
        <button onClick={this.remove}>点击卸载组件</button>
      </div>
    )
  }
 // 组件是否能更新,必须有返回值,返回值为true或false,true允许组件更新,false不允许组件更新,不手动写这个方法时,react默认返回true
  shouldComponentUpdate(){
    console.log('<Count/> - shouldComponentUpdate');
    return true;
  }
  // 组件即将更新
  componentWillUpdate(){
    console.log('<Count/> - componentWillUpdate');
  }
  // 组件完成更新
  componentDidUpdate(){
    console.log('<Count/> - componentDidUpdate');
  }
  // 组件将要卸载
  componentWillUnmount(){
    console.log('<Count/> - componentWillUnmount');
  }
}
// 点击+1按钮,按顺序打印shouldComponentUpdate->componentWillUpdate->render->componentDidUpdate
// 点击卸载组件按钮执行componentWillUnmount钩子

图片线路3–forceUpdate流程
forceUpdate用于state没有更新,还需要更新组件的情况

class Count extends React.Component{
  state = {count:0}
  force= ()=>{
    this.forceUpdate();
  }
  // 组件渲染更新
  render(){
    console.log('<Count/> - render');
    return (
      <div>
        <button onClick={this.force}>点击强制更新</button>
      </div>
    )
  }
  // 组件即将更新
  componentWillUpdate(){
    console.log('<Count/> - componentWillUpdate');
  }
  // 组件完成更新
  componentDidUpdate(){
    console.log('<Count/> - componentDidUpdate');
  }
} // 点击强制更新按钮,打印顺序componentWillUpdate->render->componentDidUpdate

图片路线4–父组件render流程
父组件的render流程说的是父组件进行render时,子组件会调用的钩子。
componentWillReceiveProps钩子在组件第一次渲染时不会被调用,之后组件被更新才会被调用

class Father extends React.Component{
  state = {carName:'bmw'}
  changeCar = ()=>{
    this.setState({carName:'bench'})
  }
  render(){
    return (
      <div>
       <h1>父组件</h1>
       <button onClick={this.changeCar}>点击换车</button>
       <Son carName={this.state.carName}/>
      </div>
    )
  }
}
class Son extends React.Component{
  // 组件将要接收参数
  componentWillReceiveProps(){
    console.log('<Son/> - componentWillReceiveProps');
  }
  render(){
    console.log('<Son/> - render');
    return (
       <div>{this.props.carName}</div>
   )
  }
  // 组件是否能更新
  shouldComponentUpdate(){
    console.log('<Son/> - shouldComponentUpdate');
    return true;
  }
  // 组件即将更新
  componentWillUpdate(){
    console.log('<Son/> - componentWillUpdate');
  }
  // 组件完成更新
  componentDidUpdate(){
    console.log('<Son/> - compon
上一篇:kafka创建多个分区时,分区会自动分配到多个不同的broker


下一篇:让查询可以使用 json path