React-类组件详解

312 阅读4分钟

类组件创建方式

ES5语法

import React from 'react'

const A = React.createClass({
    render() {
        return (
          <div>hi</div>
        )
    }
})
export default A

ES6语法

import React from 'react';

class B extends React.Component {
    constructor(props) {
       super(props);
    }
    render() {
       return (
         <div>hi</div>
      )
    }
}
export default B;

ES5 VS ES6

  • ES 6方法更好
  • 如果浏览器不支持IE 8, 可以使用webpack + babelES 6翻译成ES 5

props

定义

props是组件对外的数据接口

作用

接受外部数据

  • 只能读取不能修改写入
  • 外部数据由父组件传递

接受外部函数

  • 在子组件调用外部函数
  • 该函数一般为父组件的函数

代码实例

初始化props

// construtor和super可以被省略不写,或者必须写全套
class B extends React.Component {
   constructor(props) {
      super(props);
    }
    render(){}
}

// 通过初始化`props`, this.props就是外部数据对象的地址

传入propsB组件

class Parent extends React.Component {
   constructor(props){
   super(props)
   this.state = {name:'frank'}
}
onClick = ()=>{}
   render(){
      return <B name={this.state.name} onClick={this.onClick}>hi</B>
}

// parent组件传入`props`给`B`组件, 外部数据被包装成为一个对象

读取props

class B extends React.Component {
    constructor(props) {
    super(props);
  }
    render(){
      return 
      <div onClick={this.props.onClick}>
         {this.props.name}
         <div>
             {this.props.children}
         </div>
     </div>
   }
}

// `B`组件通过`this.props.xxx`读取`props`

子组件禁止修改写入props 理由:

  • 修改props的值,即修改外部数据的地址。例如this.props = {/*另外一个对象*/}。既然是外部数据,就应该由外部更新
  • 修改props的属性,例如this.props.xxx ='hi。既然是外部数据,就不应该从内部组件来修改值
  • 外部数据就由外部数据的主人,即父组件对其进行修改

相关钩子

componentWillReceiveProps

  • 当组件接受新的props时,会触发特殊的函数,即钩子hooks
  • 现在更名为UNSAFE_componentWillReceiveProps,但是已经被启用。不推荐使用该钩子

state

定义

state是组件对内的数据接口

代码实例

初始化state

class B extends React.Component {
    constructor(props) {
    super(props);
     this.state = {
       user: {name:'frank', age:18}
    }
  }
render() { /* ... */ }
}

读取state

this.state.user

修改statethis.setState(newState或者fn)

this.setState({x: this.state.x+1}) // 或者
this.setState((state)=>({x:state.x+1})) // 推荐这种方法

// setState是异步操作,不会立刻改变`this.state`,会等同步任务执行完,再去更新this.state
// show merge 会将新的state和旧的state进行合并

this.setState((state,props)=> newState,fn)
// 也推荐使用这种方式,更好理解,回调函数fn会在写入成功后执行

注意事项

this.state.n+=1
this.setState(this.state)

// 这种写法不会报错,但是不推荐使用。因为state为不可变数据immutable data,React不希望我们修改旧的state。所以推荐保留旧的数据的同时新建对象来操作state。例如 setState({n: state.n+1})

生命周期React-lifeCycle

类似原理

let div = document.createElement('div')
// div的create/construct过程

div.textContent = 'hi'
// 初始化state

document.body.appendChild(div)
// 将div mount到body里,即挂载

div.textContent ='hi2'
// div的update过程

div.remove()
// div的unmount过程,即从DOM中移除

React的组件也有这些过程,称之为生命周期

生命周期

生命周期-必学

生命周期函数 说明
constructor 在这里初始化state
shouldComponentUpdate() 决定是否更新组件
render 创建虚拟DOM
componentDidMount() 组件已被挂载在DOM
componentDidUpdate() 组件已被更新
componentWillUnmount() 组件被移除DOM, 将消亡

constructor

用途

  • 初始化state, 但是不能在此时调用setState
  • 可以省略不写
  • 绑定事件
constructor(){
    *******
    this.onClick = this.onClick.bind(this)
}
// 或者这样写

   onclick = ()=>{}
   constructor({
       ********
   }

shouldComponentUpdate

用途

  • 返回true表示不阻止UI更新
  • 返回false表示阻止UI更新
  • 它允许开发者手动设置判断语句,来决定组件是否进行更新。根据不同的应用场景设置不同的返回值,避免没有必要的更新

代码实例

shouldComponentUpdate(newProps, newState){
    if(newState.n === this.state.n){
        return false
    }else{
        return true
    }
}

React内置的React.PureComponent会在render 之前对比新state和旧state的每一个key,以及新props和旧props的每一个key。 如果所有key的值全都一样,就不会render;如果有任何一个key的值不同,就会render

render

用途

  • 渲染虚拟DOM,展示视图
  • 只能有一个根元素,如果有两个根元素需要使用<React.Fragment></Fragment>, 可以缩写为<></>

技巧

  • render里面可以写if...else...
  • render里面可以写? true: false表达式
  • render里面不可以直接写for循环,需要用到数组
  • render里面可以写array.map循环

componentDidMount

用途

  • 首次渲染时会执行这个函数
  • 在元素挂载到DOM后执行代码
  • 比如想获取div的高度
  • 比如想发起加载数据的AJAX请求

componentDidUpdate

用途

  • 首次渲染时不会执行这个函数
  • 在视图更新后执行代码
  • 比如在这里也可以发起更新数据的AJAX请求,更新数据
  • 不能使用setState()会引起无线循环,除非放在条件判断语句里
  • 比如reutn false, 就不会触发这个函数

componentWillUnmount

用途

  • 组件将要被移除页面时,将要被销毁时执行代码
  • unmount移除挂载的组件不会再次unmount移除挂载

注意事项

  • 如果在componentDidMount中监听了window scroll,那么就要在componentWillUnmount里取消监听
  • 如果在componentDidMount中创建了Timer,那么就要在componentWillUnmount里取消Timer
  • 如果在componentDidMount中创建了AJAX请求,那么就要在componentWillUnmount里取消AJAX请求
  • 这样做的目的是节约资源,不影响浏览器性能

更多信息

React16 生命周期函数深入浅出

React入门系列(四)组件的生命周期