关于 React 的类组件

151 阅读4分钟

1、Props - 外部数据

  • 传入 props 给 B 组件
class Parent extends React.Component{
    constructor(props){
        super(props)
        this.state = {name:'wbh'}
    }        
    onClick = ()={}
    render(){
        return <B name = {this.state.name}
        onClick = {this.onClick}>hi</B>
    }
}
    • 外部数据被包装成一个对象
    • {name:'wbh',onClick:...,children:'hi'}
    • 此处的 onClick 是一个回调
  • 读取 props

class Parent extends React.Component{
    constructor(props){
        super(props)
    }
    render(){
        return <div onClick = {this.props.onClick}>
                {this.props.name}
                    <div>{this.props.children}</div>
                </div>
    }
}
//this.props.children 就是 'hi'
//通过 this.props.xxx 来读取
  • 不准写 props

2、props 相关钩子

  • componmentWillReceiveProps 钩子
    • 当组件接受新的 props 时,会触发此钩子
    • 钩子也就是特殊函数
    • 但是这个钩子已经被弃用了
    • 更名为 UNSAFE_componmentWillReceiveProps
  • 其他被弃用的钩子:
    • componentWillMount()
    • componentWillUpdate()

3、Props 的作用

  • 接受外部数据

    • 只能读不能写
    • 外部数据由父组件传递
  • 接受外部函数

    • 在恰当的时机,调用该函数
    • 该函数一般是父组件的函数
  • 示例:

class App extends React.Component{
    constructor(props) {
      super(props);
      this.state = {
          x:1
      }
    }
    onClick = () => this.setState({x:this.state.x + 1 })
    render() {
      return (
        <div>
            <B name = {this.state.x} onClick = {this.onClick}/>
        </div>
}

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

4、读写 state

  1. 读用 this.state

  2. 写用 this.setState(newState, fn)

    • 示例:onClick = ()=>{ this.setState({x: this.state.x + 1}) }
    • 注意 setState 不会立刻改变 this.state,会在当前代码运行完后,再去更新 this.state,从而触发 UI 更新
    • this.setState((state,props)=>newState,fn)(更推荐)
    • 示例:onClick2 = ()=>{ this.setState((state,props) => ({x: state.x + 1})) }
  3. 写时会 shallow merge: setState 会自动将新 state 与旧 state 进行一级合并

5、生命周期

  1. 类比于
let div = document.createElement('div')
//这是 div 的 create/construct 过程
div.textContent = 'hi'
//这是初始化 state
document.body.appendChild(div)
//这是 div 的 mount 过程
div.textContent = 'hi2'
//这是 div 的 update 过程
div.remove()
//这是 div 的 unmount 过程
  1. 函数列表
    • constructor() - 在这里初始化 state
    • shouldComponentUpdaet() - return false 组织更新
    • render() - 创建虚拟 DOM
    • componentDidMount() - 组件已经出现在页面
    • componentDidUpdate() - 组件已经更新
    • componentWillUnmount() - 组件将要卸载、死亡

5、constructor

  • 用途
    • 初始化 props
    • 初始化 state,但此时不能调用 setState 来设置
    • 可不写
    • 用来写 bind this
constructor(){
    ...
    this.onClick = this.onClick.bind(this)
}
//这种写法等价于
onClick = () => { }
constructor(){...}

6、shouldComponentUpdate

  • 用途
    • 返回 true 表示不阻止 UI 更新
    • 返回 false 表示阻止 UI 更新
    • 示例:
class App extends React.PureComponent{
  constructor() {
    super();
    this.state = {
      n:1
    }
  }
  onClick = () => {
    this.setState((state) => ({
      n: state.n + 1
    }));
    this.setState((state) => ({
      n: state.n - 1
    }))
  }
  render() {
    console.log('render了1次')
    return (
      <div>
        App
        <div>
          {this.state.n}
          <button onClick={this.onClick}>+1</button>
        </div>
      </div>
    )
  }
}
  • 面试常问:shouldComponentUpdate 有什么用

  • 答:它允许我们手动判断是否要进行组件更新,我们可以根据应用场景灵活地设置返回值,以避免不必要的更新

  • React.PureComponent 是 React 内置的可代替 shouldComponentUpdate 的一个方法,用于代替 React.Copmonent

    • PureComponent 会在 render 之前对比新 state 和旧 state 的每一个 key,以及新 props 和旧 props 的每一个 key。
    • 如果所有 key 的值全都一样,就不会 render;如果有任何一个 key 的值不同,就会 render。
    • 示例:
class App extends React.PureComponent{
    ...
}

7、render

  • 用途
    • 展示视图
    • return (
      )
    • 只能有一个根元素(div)
    • 如果有两个根元素,就要用<React.Fragment> 包起
    • <React.Fragment /> 可以缩写成 <></>
  • 技巧
    • render 里面可以写 if...else
    • 示例;
render(){
    let message
    if(this.state.n % 2 === 0){
        message = <div>偶数</div>
    }else{
        message = <div>奇数</div>
    }
    return (
        <>
            {message}
            <button>+1</button>
        </>
    )
}
    • render 里面可以写 ?: 表达式
    • 示例:
render(){
    return (
        <div>
            {this.state.n % 2 === 0?
            <div>偶数</div>:
            <div>奇数</div>
            }

            //只显示偶数的时候
            {this.state.n % 2 === 0 && <div>偶数</div>}
        </div>
    )
}
    • render 里面不能直接写 for 循环,for 循环无法 return,需要使用数组
    • 示例:
render(){
    let result;
    for(let i=0; i<this.state.array.length;i++){
        result.push(this.state.array[i])
    }
    return result
}
    • render 里面可以写 array.map (循环)
    • 注意:所有循环都要加上 key
    • 示例:
render(){
    return this.state.array.map(n => <div key={n}>{n}</div>)
}

8、componentDidMount

  • 用途

    • 在元素插入页面后执行代码,这些代码依赖 DOM
    • 比如想要获取 div 的高度,就最好在这里写
    • 此处可以发起加载数据的 AJAX 请求(官方推荐)
    • 首次渲染会执行此钩子
  • 此钩子不接受参数

    • 示例1:
constructor(){
    ...
    this.state = {
        width: undefined
    }
}
componentDidMount() {
  const xxx = document.querySelector('#xxx')
  const width = xxx.getBoundingClientRect().width
  this.setState(state => ({
    width
  }))
}
render() {
  return (
    <div id="xxx">
        {this.state.width}px
    </div>
  )
}
    • 示例2:
//不使用 id 来获取元素,使用 ref
divRef = undifined
constructor(){
    ...
    this.divRef = React.createRef()
}
componentDidMount() {
  const div = this.divRef.current
  const width = div.getBoundingClientRect().width
  this.setState(state => ({
    width
  }))
}
render() {
  return (
    <div ref={this.divRef}>
        {this.state.width}px
    </div>
  )
}

9、componentDidUpdate

  • 用途
    • 在视图更新后执行代码
    • 此处也可以发起 AJAX 请求,用于更新数据
    • 首次渲染不会执行此钩子
    • 在此处 setState 可能会引起无限循环,除非放在 if 中
    • 若 shouldComponentUpdate 返回 false,则不触发这个钩子
  • 参数:prevProps, prevState

10、componentWillUnmount

  • 用途
    • 组件将要被移除页面然后被销毁时执行代码
    • unmount 过的组件不会再次 mount
  • 举例
    • 比如在 componentDidMount 里面监听了 window.scroll、Timer、AJAX 请求等,那么就要在 componmentWillUnmount 中取消请求
  • 也可以不写

11、钩子执行顺序