React2:函数组件和类组件

104 阅读4分钟

写法

1、函数组件

function Welcome(props){
  return <h1> Hello,{props.name} </h1>
}
使用:<Welcome name='frank'/>

2、类组件

class Welcome extends React.Component {
  render(){
    return <h1> Hello,{this.props.name} </h1>
  }
}
使用:<Welcome name='frank' />

组件逻辑

  • 翻译过程 1、
    会被翻译为 React.createElement('div');

2、 会被翻译为 React.createElement(Welcome);

3、可在Babel online上查看翻译结果

  • React.createElement 的逻辑 1、如果传入一个字符串 'div',则会创建一个 div;

2、如果传入一个函数,则会调用该函数,获取其返回值;

3、如果传入一个类,则在类前面加个 new(这会执行 constructor),获取一个组件对象,然后调用对象的render 方法,获取其返回值。

读写数据

2、类组件:this.state读数据,this.setState写数据;

3、函数组件:const [n,setN] = React.useState(0)返回数组,第一个参数 n 读,第二个参数 setN 用来写,useState()括号中的是初始值。

2、类组件直接读取属性 this.props.xxx

3、函数组件直接读取参数 props.xxx

注意事项

  • 类组件注意事项 1、React 没有像 Vue 监听 data 一样监听 state,当 this.state.n +=1 时,其实 n 已经改变了,只不过 UI 不会自动更新而已,调用 setState 才会触发 UI 更新(一部更性);

2、setState 之后,state 不会马上改变,立马读 state 会失败,更推荐的方式是 setState(函数);

//n 的初始值为0;
add(){
  this.setState({n:this.state.n+1}) //n 为 1
  coonsole.log(this.state.n)  // 打印 0
}

//用setState(函数):
add(){
  this.setState(state=>{
    const n = state.n + 1  //n 为 1
    console.log(n)  //打印 1
    return {n}
  })
}

3、this.setState(this.state) 不推荐,React 希望我们不要修改旧 state(不可变数据),常用代码:setState({n:state.n+1})

  • 函数组件注意事项 1、跟类组件类似的地方:也要通过 setX(新值) 来更新 UI;

2、更类组件不同的地方:没有 this,一律用参数和变量。

复杂 state

-类组件里有 n 和 m

class Son extends React.Component {
  constructor(){
    super()
    this.state = {
      n:0,
      m:0
    }
  }
  addN(){
    this.setState({n:this.state.n+1})
  }
  addM(){
    this.setState({m:this.state.m+1})
  }
  render(){
    <div>
      n:{this.state.n}
      <button onClick = { ()=>{this.addN()} }>+1</button>
      m:{this.state.m}
      <button onClick = { ()=>{this.addM()} }>+1</button>
    </div>
}
const GrandSon = ()=>{
  const [n,setN] = React.useState(0)
  const [m,setM] = React.useState(0)
  return (
    <div>
      n:{n}
      <button onClick=()=>{setN(n + 1)}>n+1</button>
      m:{m}
      <button onClick=()=>{setM(m + 1)}>m+1</button>
    </div>
  )
}
const GrandSon = ()=>{
  const [state,setState] = React.useState({
    n:0,
    m:0
  })
  return(
    <div>
      n:{state.n}
      <button onClick = {()=>setState({n:state.n+1})}> n+1 </button>
      m:{state.m}
      <button onClick = {()=>setState({m:state.m+1})}> m+1 </button
    </div>
  )
}
class Son extends React.Component {
  constructor(){
    super()
    n:0,
    m:0,
    user:{
      name:'frank',
      age:18
    }
  }
  addN(){
    this.setState({n:this.state.n + 1})
  }
  changeUser(){
    this.setState({
    //m 和 n 不会被置空
      user:{
        name:'jack'
        // age 被置空
      }
    })
  }
  render(){
    <div>
      n:{this.state.n}
      <button onClick={()=>this.addN()}>n+1</button>
      <hr/>
      <div>user.name:{this.state.user.name}</div>
      <div>user.age:{this.state.user.age}</div>
      <button onClick={() => this.changeUser()}>change user</button>
    </div>
  }
}
  • 用 ... 操作符,或 Object.assign,使 m 不被置空
changeUser(){
    this.setState({
    //m 和 n 不会被置空
      user:{
      ...this.state.user
        name:'jack'
        // age 被置空
      }
    })
  }
  
changeUser(){
  const user = Object.assign({},this.state.user)
  user.name = 'jack'
  this.setState({
    user:user
  })
}
  • 总结 1、类组件的 setState 会自动合并第一层属性;

2、但是不会合并第二层属性;

3、使用 Object.assign 或 ...操作符;

4、函数组件的 setX 则完全不会自动合并,必须用 ...操作符合并

事件绑定

  • 事件绑定写法 image.png

  • 两种写法区别 1、蓝色函数(箭头函数)是对象本身的属性,这意味着每个 Son 组件都有自己的 addN,如果有两个Son,就有两个 addN;

2、红色函数是对象的公用属性,也就是原型上的属性,这意味这所有 Son 组件公用一个 addN;

3、以下代码可证明:

image.png

class Person2 {
  sayHello = ()=>{}
}
相当于:
class Person2 {
  constructor(){
    this.sayHello = ()=>{}
  }
}
  • 为什么 this 会变/不会变 1、所有函数的 this 都是参数,由调用决定,所以可变;

2、唯独箭头函数的 this 不变,因为箭头函数不接受 this 作为参数,箭头函数的 this 是定义的时候确定,后面就不能再改了。

this 例题

var a = {
  name:"里面的name",
  sayName:function(){
    console.log('this.name' + this.name)
  }
}
var name = '外面的name'
function sayName(){
  var sss = a.sayName
  sss()  // sss.call() ---> this 是 window,打印‘外面的name ’
  a.sayName() //a.sayName.call(a) --->this 是 a,打印‘里面的name’
  (a.sayName)()  //a.sayName.call(a) --->this 是 a ,打印‘里面的name’
  (b = a.sayName)()  //b.call() --->this 是 window , 打印‘外面的name’
}
sayName()  //sayName.call() --->call 的第一个参数为空,所以 this 为 null ,null 自动替换为 window ,所以这里的 this 就是 window
var length = 10
function fn(){
  console.log(this.length)
}
var obj = {
  length:5,
  method:function(fn){
    fn()  // fn.call() --->this 是 window , 打印 10
    arguments[0]()  // arguments[0].call(arguments),this 是 arguments,也就是 [fn,1],数组长度为2 ,所以打印 2
  }
}
obj.method(fn,1)  //obj.method.call(obj,arguments[fn,1]] ,this 是 obj

React V.S. Vue

  • 相同点 1、都是对视图的封装,React 是用类和函数表示一个组件,而 Vue 是通过构造选项构造一个组件;

2、都提供了 createElement 的 XML 简写,React 提供的是 JSX 语法,而 Vue 提供的是模板语法(v-for/v-if...)

  • 不同点 React 是把 HTML 放在 JS 里写(HTML in JS),而 Vue 是把 JS 放在 HTML 里写(JS in HTML)