浅析React 类组件和函数组件

284 阅读3分钟

类组件和函数组件

Element vs Component

const div = React.createElement("div")//这是一个React元素
const Div =()=>React.createElement("div")//这是React一个组件

React两种组件

  • 函数组件

function Welcome(props) {
  return <h1>Hello,{props.name}</h1>;//读取props
}
使用方法<Welcome name="leehome"/>

  • 类组件

class Welcome extends React.Component {
    constructor() {
        super();
    }

    render() {
        return <h1>Hello,{this.props.name}</h1>;//读取props  }}
使用方法:<Welcome name="leehome"/>

tips

<div/>会被翻译成React.createElement("div"),

<Welcome/>翻译为React.createElement(Welcome)

具体可以用babel online 直接翻译查看

React.createElement的逻辑

  • 如果传入一个字符串"div",则会创建一个div
  • 如果传入一个函数,则会调用该函数,获取其返回值
  • 如果传入一个类,则会在类前面加个new,获取一个组件对象,然后调用对象的render方法,获取其返回值

如何使用props和state

添加props

<Welcome name="leehome"/>

类组件直接读取属性: this.props.name

函数组件直接读取参数:props.name

添加state

类组件用this.state读,this.setState写(setState尽量用函数形式)

this.setState ({n:this.state.n+1})
//this.setState(state=>({n:state.n+1}))

函数组件用useState返回数组,第一项读,第二项写(写尽量用函数形式)

setN(n+1)
//setN(x=>x+1)

类组件注意事项

this.state.n+=1 改变了n,但是UI不是自动更新而已,调用setState才会触发UI更新(异步更新)。

函数组件注意事项

  • 跟类组件类似的地方

也要通过setX(新值)来更新UI

  • 跟类组件不同的地方

没有this,一律用参数和变量

两种编程模式

Vue的编程模型:一个对象对应一个虚拟DOM,当对象的属性改变时,把属性相关的DOM节点全部更新(注:Vue为了其他考量,也引入了虚拟DOM和DOM diff,下图只是简化)

React的编程模型:一个对象,对应一个虚拟DOM,另一个对象,对应另一个虚拟DOM,对比两个虚拟DOM,找不同最后局部更新DOM。

复杂state

如果state里面不止有n:

  • 类组件里面有n和m

class Son extends React.Component {
  constructor() {
    super();
    this.state = {
      n: 0,
      m: 0
    };
  }
  addN() {
    this.setState({ n: this.state.n + 1 });
    // m 会被覆盖为 undefined 吗?
  }
  addM() {
    this.setState({ m: this.state.m + 1 });
    // n 会被覆盖为 undefined 吗?
  }
  render() {
    return (
      <div className="Son">
        儿子 n: {this.state.n}
        <button onClick={() => this.addN()}>n+1</button>
        m: {this.state.m}
        <button onClick={() => this.addM()}>m+1</button>
        <Grandson />
      </div>
    );
  }
}

类组件的setState会自动合并第一层属性,但不会合并第二层属性,我们可以Object.assign或者...操作符:

  class Son extends React.Component {
  constructor() {
    super();
    this.state = {
      n: 0,
      m: 0,
      user: {
        name: "frank",
        age: 18
      }
    };
  }
  addN() {
    this.setState({ n: this.state.n + 1 });
    // m 会被覆盖为 undefined 吗?
  }
  addM() {
    this.setState({ m: this.state.m + 1 });
    // n 会被覆盖为 undefined 吗?
  }
  changeUser() {
    this.setState({
      // m 和 n 不会被置空
      user: {
        ...this.state.user, // 复制之前的所有属性
        name: "jack"
      }
    });
  }

  • 函数组件里面和n和m

函数组件的setX则完全不会帮你合并,要合并可以用...操作符。

事件绑定

类函数的事件绑定(最好用)

class Son extends React.Component{
addN = () => this.setState({n: this.state.n + 1});
//constructor(){
this.addN = ()=> this.setState({n: this.state.n + 1})
} 
上面两种写法等价
render(){
return <button onClick={this.addN}>n+1</button>
  }
}

如果这样写的话:

addN(){ 
this.setState({n: this.state.n + 1})
}//addN: functioin(){
this.setState({n: this.state.n + 1})
}

下面这种写法的addN在原型上,this可变成window,上面的写法在对象上,this不会变成window。

tips

所有的函数的this都是参数,由调用决定,所以可变

唯独箭头函数的this不变,箭头函数不接受this

 

this 的指向可参考我的博客 js函数中的this


如有错误,请留言指正!!!