React class 组件详解

133 阅读3分钟

创建class的方式(推荐ES6)

import React from 'react'; 
class B extends React.Component { 
  constructor(props) { 
    super(props); 
  } 
  render() { 
    return (
      hi
    ) 
  } 
} 
export default B;
  • 第二三四行可以直接删掉,如果要在里面加额外的代码,就写;如果只有这三行就可以省掉。

props(外部数据)

image.png

初始化

class B extends React.Component{
  constructor(props){
    super(props)
  }
  render(){}
}

要么不初始化,即不写constructor

要么初始化,且必须写全套(不写super直接报错)

效果:这么做了之后,this.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>
  } 
}
//通过this.props.xxx 读取
  • 永远不许写props

image.png

相关钩子

export default class App extends React.Component {
  constructor(props){
    super(props)
    this.state = {
      x:1
    }
  }
  onClick = ()=>{
    this.setState((state)=>{
      return {x:state.x+1}
    })
  }
  render(){
    return (
      <div className="App">
        App <button onClick={this.onClick}>+1</button>
        <B n={this.state.x}/>
      </div>
    );
  }
}
class B extends React.Component{
  componentWillReceiveProps(newProps){
    console.log('旧的 props 为')
    console.log(this.props)
    console.log('新的 props 为')
    console.log(newProps)
    // 注意 console 的延迟计算 bug
  }
  render(){
    return <div>B {this.props.n}</div>
  }
}

componentWillReceiveProps钩子

  • 当组件接受新的props时,会触发此钩子

  • 啥是钩子?黑话,将其翻译成【特殊函数】即可

  • 该钩子已被弃用,更名为UNSAFE_componentWillReceiveProps,不要使用该钩子

props 的作用

接受外部数据

  • 只能读不能写

  • 外部数据由外组件传递

接受外部函数

  • 在恰当的时机,调用该函数

  • 该函数一般是父组件的函数

State & setState(内部数据)

初始化State

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

读写State

读用this.state

  • this.state.xxx.yyy.zzz

写用this.setState(???,fn)

  • this.setState(newState,fn)

  • 注意setState不会立刻改变this.state,会在当前代码运行完后,再去更新this.state,从而触发UI更新

  • this.setState((state,props)=>newState,fn),这种方式的state反而更易于理解,fn会在写入成功后执行

image.png

  • 推荐第二种写法

写时会shallowmerge

  • setState会自动将新state与旧state进行一级合并(React 只会检查新 state 和旧 state 第一层的区别,并把新 state 缺少的数据从旧 state 里拷贝过来)

修改this.state的属性值(不推荐用)

  • this.state.n +=1

  • this.setState(this.state)

生命周期

image.png

函数列表

  • constructor() -- 在这里初始化state

  • static getDerivedStateFromProps()

  • shouldComponentUpdate() -- return false阻止更新(不要忘了return true)

  • render() -- 创建虚拟DOM

  • getSnapshotBeforeUpdate()

  • componentDidMount() -- 自减已出现在页面

  • componentDidUpdate() -- 组件已更新

  • componentWillUnmount() -- 组件将死

  • static getDerivedStateFromError()

  • componentDidCatch()

constructor

image.png

shouldComponentUpdate

用途

  • 返回true表示不阻止UI更新

  • 返回false表示阻止UI更新

class App extends React.Component {
  constructor(props) {
    super();
    this.state = {
      n: 1,
    };
  }
  onClick = () => {
    this.setState((state) => ({n: state.n + 1 }));
    this.setState((state) => ({n: state.n - 1 }));
  };
  shouldComponentUpdate(newProps, newState){
    if(newState.n === this.state.n){
      return false 
    }else{
      return true
    }
  }
  render() {
    console.log('render 了一次')
    return (
      <div>
        {this.state.n}
        <button onClick={this.onClick}>+1-1</button>
      </div>
    )
  }
}

image.png

React.PureComponent

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

image.png

render

用途

  • 展示视图return (<div>...</div>)

  • 只能有一个根元素

  • 如果有两个跟元素,就要用<React.Fragment>包起

  • <React.Fragment/>可以缩写成<></>

技巧

  • render里面可以写if...else
render() {
    let message;
    if (this.state.n % 2 === 0) {
      message = <div>偶数</div>;
    } else {
      message = <span>奇数</span>;
    }
    return (
      <>
        {message}
        <button onClick={this.onClick}>+1</button>
      </>
    );
  }
  • render里面可以写?:表达式(或者&&)
render() {
    return (
      <>
        {this.state.n % 2 === 0 ?
          <div>偶数</div>:
          <span>奇数</span>}
        <button onClick={this.onClick}>+1</button>
      </>
    );
  }
render() {
    return (
      <>
        {this.state.n % 2 === 0 && <div>偶数</div> }
        <button onClick={this.onClick}>+1</button>
      </>
    );
  }
}
  • render里面不能直接写for循环,需要用数组

image.png

  • render里面可以写array.map (循环)

image.png

所有的循环必须写key

componentDidMount()

image.png

用途

  • 在元素插入页面后执行代码,这些代码依赖DOM

  • 比如你想获取div的高度,就最好在这里写

  • 此处可以发起加载数据的AJAX请求(官方推荐)

  • 首次渲染会执行此钩子

image.png

建议用divRef的时候先声明divRef = undefined

componentDidUpdate()

image.png

用途

  • 在视图更新后执行代码

  • 此处也可以发起AJAX请求,用于更新数据

  • 首次渲染不会执行此钩子

  • 在此处setstate可能会引起无线循环,除非放在if里

  • 若shouldComponentUpdate返回false,则不触发次钩子

componentWillUnmount

image.png

用途

  • 组件将要被移出页面然后被销毁时执行代码

  • unmount过的组件不会再次mount

image.png

分阶段看钩子执行顺序

image.png