React 类组件

创建 Class 组件

  1. ES5 方式(过时)

    import React from 'react'
    
    const A = React.createClass({
        render(){
            return(<div>hi</div>)
        }
    })
    export default A
    // 由于 ES5 不支持 class,才会有这种方法
    
  2. ES6 方式

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

props

传入 props 给 B 组件

class Parent extends React.Component {
    constructor(props){
        super(props)
        this.state = {name: 'frank'}
    }
    onClick = () => {}
    render(){
        return(
        <B name={this.state.n} onClick={this.onClick}>hi</B>
        )
    }
}
// 外部数据被封装为一个对象
// {name: 'frank', onClick:...,children: 'hi'}

初始化

class B extends React.Component{
    constructor(props){
        super(props)
    }
    render(){...}
}
// this.props 就是外部数据 对象的地址 了

读取

class B extends React.Component{
    constructor(props){
        super(props)
    }
    render(){
        return(
            <div onClick={this.props.onClick}>
            {this.props.name}
                <div>{this.props.chrldren}</div>
            </div>
        )
    }
}
// 通过 this.props.xxx 读取

props 的作用

接受外部数据

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

接受外部函数

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

state & setState

初始化

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

读写 State

this.state

this.state.user.name


this.setState(???,fn)

this.setState(newState, fn)

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

this.setState((state, props) => newState, fn)

这种方式的 state 更容易理解

fn 会在写入成功后执行。

shallow merge: setState 会自动将新的 state 与 旧的 state 进行一级合并。

onClick = () => {
  this.setState({ x: this.state.x + 1 });
};

onClick2 = () => {
  this.setState( (state) => ({ x: state.x + 2 }) );
};


onClick = () => {
  this.setState(
    {
      x: this.state.x + 1,
    },
    // callback
    () => {
      this.setState({ x: this.state.x + 1 });
    }
  );
};

修改 this.state 的属性值,不推荐用!

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

生命周期

生命周期图谱


类比如下代码

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 过程

函数列表

constructor()

static getDerivedStateFromProps()

shouldComponentUpdate()

render()

getSnapshotBeforeUpdate()

componentDidMount()

componentDidUpdate()

componentWillUnmount()

static getDerivedStateFromError()

componentDidCatch()


函数列表-必会

constructor() - 在这里初始化 state
shouldComponentUpdate() - return false 阻止更新
render() - 创建虚拟 DOM
componentDidMount() - 组件已出现在页面
componentDidUpdate() - 组件已更新
componentWillUnmount() - 组件将死

constructor

用途:

初始化 props

初始化 state,但此时不能调用 setState

用来写 bind this

constructor(){
    ...
    this.onClick = this.onClick.bind(this)
}

可以用新语法代替

constructor(){...}
onClick = () => {}

shouldComponentUpdate

用途:

返回 true 表示不阻止 UI 更新

返回 false 表示阻止 UI 更新

面试常问:shouldComponentUpdate 有什么用?

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

import React from "react";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      n: 1,
    };
  }
  onClick = () => {
    this.setState((state) => ({ n: state.n + 1 }));
    this.setState((state) => ({ n: state.n - 1 }));
  };
	// {n:1} 和 {n:1}
  shouldComponentUpdate(nextProps, nextState) {
      // 阻止渲染
    if (nextState.n === this.state.n) {
      return false;
    } else {
      return true;
    }
  }
  render() {
    console.log("render了一次");
    return (
      <div>
        App组件<br />
        {this.state.n}
        <button onClick={this.onClick}>+1</button>
      </div>
    );
  }
}
export default App;

可以使用 React.PureComponent 替代 React.Component 实现 shouldComponentUpdate()

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

官方文档

注意

React.PureComponent 中的 shouldComponentUpdate() 仅作对象的浅层比较。如果对象中包含复杂的数据结构,则有可能因为无法检查深层的差别,产生错误的比对结果。

仅在你的 props 和 state 较为简单时,才使用 React.PureComponent


render

用途:

展示视图 return (<div> ... </div>),只能有一个根元素。

两个根元素,要用 <React.Fragment> 包起,可以缩写为 <> </>

技巧:

render 里面可以写 if...else?:表达式

不能直接写 for循环,需要用数组

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

class App extends React.PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      n: 1,
      array: [1, 2, 3]
    };
  }
  onClick = () => {
    this.setState((state) => ({ n: state.n + 1 }));
  };
// if...else
  render() {
   let message
   if(this.state.n%2 === 0){
     message = <span>偶数</span>
   }else{
     message = <span>奇数</span>
   }
   return(
     <React.Fragment>
     {message}
     <button onClick={this.onClick}>+1</button>
     </React.Fragment>
   )
  }
// ? :
  render() {
    return (
      <>
        {this.state.n % 2 === 0 ?
        <span>偶数</span> :
        <span>奇数</span>}
        <button onClick={this.onClick}>+1</button>
      </>
    );
  }
// for 循环
  render() {
    let result = [];
    for (let i = 0; i < this.state.array.length; i++) {
      result.push(this.state.array[i]);
    }
    return result;
  }
// for 循环 map()
render() {
    return this.state.array.map((n) => <span key={n}>{n}</span>);
  }
}

componentDidMount()

用途:

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

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

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

首次渲染 会执行此钩子

官方文档

// 想获取 div 的高度
...
componentDidMount(){
  const div = document.querySelector('#xxx');
  const {width} = div.getBoundingClientRect()
  this.setState({width})
}
render() {
  return(
    <div id='xxx'>hello, width, {this.state.width}px</div>
  )
}

改用 ref

class App extends React.PureComponent {
  divRef = undefined;
  constructor(props) {
    super(props);
    this.state = {
      n: 1,
      width: undefined,
    };
    this.divRef = React.createRef();
  }

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

  componentDidMount() {
    const div = this.divRef.current;
    const { width } = div.getBoundingClientRect();
    this.setState({ width });
  }

  render() {
    return <div ref={this.divRef}>hello, width: {this.state.width}px</div>;
  }
}

ref 官方文档


componentDidUpdate()

用途:

在视图更新后执行。第一次渲染不执行。

此处也可以发起 Ajax 请求,用于更新数据文档)。

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

在此处 setState 可能会引起无限循环,除非放在 if 里。

若 shouldComponentUpdate 返回 false,则不会触发此钩子。


componentWillUnmount()

用途:

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

unmount 过的组件不会再次 mount

举例:

  • 如果你在 c…DidMount 里面监听了 window scroll

    那么你就要在 c…WillUnmount 里面取消监听

  • 如果你在 c…DidMount 里面创建了 Timer

    那么你就要在 c…WillUnmout 里面取消 Timer

  • 如果你在 c…DidMount 里面创建了 Ajax 请求

    那么你就要在 c…WillUnmount 里面取消请求

  • 否则你就是菜逼。

官方文档


生命周期回顾

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

  • shouldComponentUpdate() - return false 阻止更新

  • render() - 创建虚拟 DOM

  • componentDidMount() - 组件已出现在页面

  • componentDidUpdate() - 组件已更新

  • componentWillUnmount() - 组件将死

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值