小鸡啄米之React状态机

状态机

React采用状态机的状态来重新渲染页面(不操作DOM),状态保存在实例变量state中,该状态初始化后必须使用setState来修改状态,否则不会触发重新渲染机制,初始化一般在构造中或者类中方法外

初始化:this.state={key:value,key,value}
修改状态:this.setState({key:value,key:value})
使用状态:this.state.key

	// 这三种修改状态的写法都是可以的
    handleClick() { 
      this.setState(state=>({
            isToggleOn:!state.isToggleOn
        })
        )
    }
    
    handleClick2() { 
        this.setState(function(state) {
            return {isToggleOn: !state.isToggleOn};
        });
    }
    // 推荐这种写法
    handleClick3() {
        this.setState({
            isToggleOn: !this.state.isToggleOn
        });
    }

构造函数使用constructor表示,且如需使用this,则必需调用super(props)进行初始化

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date:new Date()};
  }
 
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>现在是 {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
 
ReactDOM.render(
  <Clock />,
  document.getElementById('example')
);

注意:组件在调用过程中不关心是否是有状态的,数据从顶向下流动,某个组件的状态只能影响其下的子组件

生命周期

生命周期控制:可以在组件挂载和卸载时做一些事情,比如释放占用的资源。比如componentDidMount这个是挂载时时,即组件输出到DOM时执行,componentWillUnmount是卸载时处理

组件生命周期可分为三个状态:
Mounting(插入真实DOM)
Updating(正在渲染)
Unmounting(移出真实DOM)

生命周期方法(按照先后顺序)

  1. 初始
    defaultProps:静态属性,用于初始化props值
    constructor:如果之后的代码需要使用props,需要先调用super(props)方法,否则有可能有bug,这里面会执行state的赋值。注意:不要在构造函数中引入副作用或者订阅,在componentDidMount中使用。
    static getDrivedStateFromProps:静态方法,在render前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。此方法无权访问组件实例。
    UNSAFE_componentWillMount() 在渲染前调用,该方法调用时表示组件对象的基础属性和方法都初始化完成。在该方法中调用this.setState不会引起组件重新渲染(因为组件此时还没有挂载到DOM上)【过时】
    render:页面触发渲染,在return前,无法通过getelement获取dom元素,render执行完,虚拟dom构建完毕才开始挂载页面。该方法之后就可以调用this.setState方法了。同时函数应该为纯函数,这意味着在不修改组件 state 的情况下,每次调用时都返回相同的结果,并且它不会直接与浏览器交互。
    componentDidMount : 在第一次渲染结束,DOM更新完毕后调用。常用来初始化页面数据,增加订阅或做异步请求获取数据。可以在 componentDidMount() 里直接调用 setState()。将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。保证了即使在 render() 两次调用的情况下,用户也不会看到中间状态。需要谨慎使用该模式,因为它会导致性能问题。通常,应该在 constructor() 中初始化 state。如果渲染依赖于 DOM 节点的大小或位置,比如实现 modals 和 tooltips 等情况下,可以使用此方式处理

  2. 更新
    static getDrivedStateFromProps:静态方法,获取props参数,16.3时setState和forceUpdate时不会触发这个函数,16.4之后就会了。
    UNSAFE_componentWillReceiveProps()(nextProps):方法,接收参数props为下一次的props值,里面this.props获取的为改变前的值。在这里改变state不会重渲染。
    shouldComponentUpdate(nextProps,nextState):返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。可以传递两个值:其中this.state为旧状态值,而nextProps,nextStates为新状态值。返回 false 以告知 React 可以跳过更新。请注意,返回 false 并不会阻止子组件在 state 更改时重新渲染。不能在这里企图阻止渲染,只能作为性能优化方式。禁止在 shouldComponentUpdate() 中进行深层比较或使用 JSON.stringify()。这样非常影响效率,且会损害性能。
    UNSAFE_componentWillUpdate()(nextProps):在组件接收到新的props时,且仅在父组件重新渲染时触发与state状态无关。在初始化时不会被调用。
    render:页面触发渲染,执行完毕才会开始挂载到页面上去,即更新DOM和refs
    static getSnapshotBeforeUpdate(preprops, prestate): 在最近一次更新渲染到Dom之前被调用(更新DOM前),可在此获得一些数值如滚动位置,该方法的返回值将作为componentDidUpdate()的第三个参数传入,如果没有调用该方法,则第三个参数为undefined
    componentDidUpdate(prevProps, prevState,snapshot): 在组件完成DOM更新后立即调用。首次渲染不会执行此方法。注意,如果在这个方法中改变state请设立好条件,否则产生无限循环。

  3. 卸载
    componentWillUnmount:在组件从 DOM 中移除之前立刻被调用。用于做一些清理工作,比如取消订阅和清除定时器等。禁止在此方法中调用this.setState

/*
当页面发生跳转后但由于前一个页面请求还没有结束,或者事件 定时器没有结束,但是页面跳转到下一个页面了,此时就会报错。
通常是 react 组件已经从 DOM 中移除,但是我们在组件中做的一些异步操作还未结束,如:接口调用等,当其完成时,执行setState操作,而此时我们已经将改组件dom移除,从而导致上述问题。

作者:zyghhhh
链接:https://www.jianshu.com/p/ea3cfc0a85da
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
/*

// 清除定时器
componentWillUnmount(){
  clearTimeout(this.timer)
}
// 解绑dom事件
componentWillUnmount(){
  //其他事件也类似
  window.onScroll = null
}
// 清除react事件
componentWillUnmount(){
  //其他事件也类似
  this.setState = (state,callback) => {
    return
  }
}
  1. 错误处理
    static getDerivedStateFromError(error):此生命周期会在后代组件抛出错误后被调用。 它将抛出的错误作为参数,并返回一个值以更新 state,比如UI降级。会在渲染阶段调用,因此不允许出现副作用(回调方法)返回值会更新state相当于setState
    componentDidCatch(error, info):会在“提交”阶段被调用,因此允许执行副作用。 它应该用于记录错误之类的情况

参考图1:
在这里插入图片描述
参考图2:
在这里插入图片描述
官网生命周期图示:注意:getDerivedStateFromProps在16.4前只有接收new props才更新!!
在这里插入图片描述
我总结的图示:
在这里插入图片描述
在绿色部分此时DOM已经更新完毕,如果再次改变状态会触发页面的重新渲染。深灰色的为过时方法,减少调用。

父子组件中的生命周期

在这种情况下:

  1. 组件初始化:render后开始构造子组件
父defaultProps
父constructor
父componentWillMount
父render
		子defaultProps
		子constructor
		子componentWillMount
		子render
		子componentDidMount
父componentDidMount
  1. 组件更新,同初始化一样,在render后进入子组件更新
在父组件中改变某个state
父shouldComponentUpdate
父componentWillUpdate
父render
		子componentWillReceiveProps
		子shouldComponentUpdate
		子componentWillUpdate
		子render
		子componentDidUpdate
父componentDidUpdate
  1. 卸载,由内向外
子componentWillUnmount
父componentWillUnmount

参考:https://developer.aliyun.com/article/780453

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值