React 的函数组件和 Class 组件

作者: 写代码的海怪 | 来源:发表于2018-12-18 15:01 被阅读2次

    组件是 React 里非常重要的组成部分,其分为函数组件和 Class 组件。本文就简单说明这两种组件定义方式的由来。

    例子

    让我们先从一个简单的需求开始。定义一个加减器,就是用来做简单的加减法。使用 JSX 语法我们可以写成这样:

    let number = 0
    let add = () => {
        number += 1
        render()
    }
    
    let minus = () => {
        number -= 1
        render()
    }
    
    let render = () => {
        ReactDOM.render(
            <div className="parent"> // Adder1
                <span className="red">{number}</span>
                <button onClick={add}>+</button>
                <button onClick={minus}>-</button>
            </div>,
            document.querySelector('#root'))
    }
    
    render()
    

    函数组件

    现在我们想要更多的加减器,那么可能会在 render() 函数里写很多个 <div className="parent">...</div>,这样明显不好。

    还记得 JSX 语法里的并不是真正的 HTML,而是虚拟 DOM,即 JS 代码,不信可看转译后的结果:

    转译结果

    既然是 JS 代码,那么我们就可以用 JS 的方法来将其分块了。我们定义多个函数,来返回虚拟 DOM 不就可以完成分块了么?所以定义两个函数:

    function App() {
      return (
        <div>
          <Adder1/> // React.createElement(Adder1)
          <Adder2/> // React.createElement(Adder2)
        </div>
      )
    }
    
    function Adder1() {
      return (
        <div className="parent">
          <span className="red">{number}</span>
          <button onClick={add}>+</button>
          <button onClick={minus}>-</button>
        </div>
      )
    }
    ...
    

    虽然这里有个问题,变量 number 被 Adder1 和 Adder2 共享了。但是 React 的一个简单组件就诞生了,其本质就是一个函数。

    props

    React 的开发者很聪明,即然这个组件返回的是虚拟 DOM,那么正常的 DOM 应该要有属性才行,而函数的参数好像和这属性有着某种相关性。所以函数组件的一个特性被开发出来了:函数组件传入的参数(对象) 代表了该虚拟 DOM 的属性。例子:

    function Adder (props) {
      return (
        <div className="parent">
          <p>My name is {props.name}, age: {props.age}</p>
        </div>
      )
    }
    
    function App() {
        return (
        <div>
          <Adder name="Adder 1" age="12"/>
        </div>
      )
    }
    

    state

    那么自身的属性呢?很简单,在函数里面定义就好了:

    function Adder1(props) {
      let name = 'hello'
      return (
        <div className="parent">
          <p>My name is {name}, age: {props.age}</p>
        </div>
      )
    }
    

    Class 组件

    好了,现在说说怎么去解决共享 number 的问题。像上面说的用自身属性试试:

    function Adder1(obj) {
      let number = 0
      function add() {...}
      function minus() {...}
      return (
        <div className="parent">
          <span className="red">{number}</span>
          <button onClick={add}>+</button>
          <button onClick={minus}>-</button>
        </div>
      )
    }
    ...
    

    虽然好像看起来没问题,但是每次修改值后我们都要重新 render 一下组件的,render 的时候需要执行 Adder1 里面的代码,number 被重置了。

    React 的 Class 组件就了为了这样的问题而诞生的:

    class Adder1 extends React.Component {
      constructor(props) {
        super(props)
        this.state = {
          number: 0
        }
      }
      
      add() {
        this.setState({
          number: this.state.number + 1
        })
      }
      minus() {
        this.setState({
          number: this.state.number - 1
        })
      }
      
      render() {
        return (
          <div className="red">
            <span>{this.state.number}</span>
            <button onClick={this.add.bind(this)}>+1</button>
            <button onClick={this.minus.bind(this)}>-1</button>
            {this.props.name}
          </div>
        )
      }
    }
    

    注意

    1. 必须要继承 React.Component
    2. constructor 里要传入 props,并调用 super(props) ,因为这是 ES6 语法的规定
    3. this.state 用来存放自身属性,但是修改的时候要用 this.setState(newState),而不能直接this.state.number += 1
    4. 绑定方法的时候要绑定this,因为 React 会这样调用 this.add.call(undefined, ...)

    setState

    为了对更新进行优化,如果多次修改 this.state 会将大批量更新合并成一次更新。其实 this.state 的更新方法属于异步更新,只有全部改变完了再去更新。

    像下面的代码只会更新一次:

    this.setState({
        number: this.state.number - 1
    })
    this.setState({
        number: this.state.number - 1
    }) // 只是一次 - 1,因为每二次的时候 this.state.number 还可能是 0
    

    当然可以用回调的形式进行多次更新:

    this.setState((state) => {
        return { number: state.number - 1 }
    })
    this.setState((state) => {
        return { number: state.number - 1 }
    })
    

    相关文章

      网友评论

        本文标题:React 的函数组件和 Class 组件

        本文链接:https://www.haomeiwen.com/subject/oxflkqtx.html