React State and Lifecycle

React State and Lifecycle

如何更新当前组件上的状态,或者说如何在组件state发生变化时,将变化之后的UI显示在界面上。

直接通过函数的方式

我们可以通过如下方式来更新UI;设置一个时间监听器,每隔固定的时间去执行一次更新函数。

function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  ReactDOM.render(
    element,
    document.getElementById('root')
  );
}

setInterval(tick, 1000);

使用自定义组件的方式

接下来将使用组件的形式来实验,先看代码部分。
- 定义一个用于更新的函数function tick(){},
- 在ReactDOM.render中更新组件状态

function Clock(props) {
  return (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {props.date.toLocaleTimeString()}.</h2>
    </div>
  );
}

function tick() {
  ReactDOM.render(
    <Clock date={new Date()} />,
    document.getElementById('root')
  );
}

setInterval(tick, 1000);

可以看到以上两种方式其实实际上在我们更新的地方,已经真实的抽离出来的组件,他们之间的耦合度还是比较高;我们希望Clock组件专门用来更新,在需要改组件的地方,直接引用而不需要传入props

将function转为class

我们可以通过如下步骤来实现

  • 创建一个ES6class,使用同样的名字;但是需要继承自React.Component
  • 在创建的勒种新建一个新的render()方法
  • 将function中的函数体,移动到render()方法中
  • props替换为this.props

经过以上步骤,我们就讲原本是函数的Clock重新定义为了Class

class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

给自定义组件添加state

  • this.props修改为this.state
class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>// this line
      </div>
    );
  }
}
  • 在构造函数中添加this.state = {date: new Date()};
    • 在这里需要注意一点,必须要有super(props),用于将props向上传递给父组件
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()}; // add this line
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
  • ReactDOM.render()中的<Clock date={new Date()} />, 替换为<Clock />,
<Clock />,
  • 最终代码
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

添加组件的生命周期处理函数

  • 当组件第一次被渲染在DOM中时,会调用componentDidMount
    我们在这里定义一个timer
  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }
  • 自定一个处理tick的函数
  tick() {
    this.setState({
      date: new Date()
    });
  }
  • 当组件不在被需要时,也就是从DOM树中被移除时,调用componentWillUnmount
    我们在这里讲timer进行移除
  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

通过以上步骤的改造,效果图如下
这里写图片描述
再次快速回顾下

  1. <Clock/>传入到ReactDOM.render()方法时,React会调动Clock组件的构造方法,在构造函数中,初始化了this.state并且在接下来的步骤中会使用到
  2. React接着会调动Clock组件的render()方法,render()方法才真正的可以让react知道需要在屏幕上显示什么,然后React更新DOM用于匹配Clock的render函数的输出
  3. Clock组件根据state输出的结果被插入到DOM中时,React会调用componentDidMount()方法,在该方法中,Clock组件向Browser请求设置一个timer,该timer用来每隔1秒调用一次当前组件的tick()方法
  4. 浏览器会按照一秒为单位区调用tick()方法。在Clock组件中,使用setState()并传入当前的最新事件来调度UI的更新。这里需要特别说明下setState(),只有setState()方法才可以让React知道当前当前的state更新了,React会根据新的状态来调用render()方法更新UI。此时,render()方法中this.state.date就和之前的不同了,所以新的render方法会根据新的state来更新
  5. 如果Clock组件从DOM树种移除之后,React会调用该组件的componentWillUnmout()方法,在这里我们需要停止timer

正确的处理state的更新

  • 不要尝试直接更新state
// Wrong
this.state.comment = 'Hello';
  • 要使用setState
// Correct
this.setState({comment: 'Hello'});
  • state的更新是异步的
    • 如这里的在setState中进行运算可能拿不到预期的结构
// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});
  • 相反,我么这里需要传入一个函数到setSate中,如下两种写法都正确
// Correct
this.setState(function(prevState, props) {
  return {
    counter: prevState.counter + props.increment
  };
});
// Correct
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));
  • state更新之后会覆盖掉之前的信息,state可以被单独更新
    这个比较好理解。这里就不举例子

数据向下传递

一般来说,每一个组件的state都是该组件私有的,不会被外界知道,更不会暴露给外界;因此它是私密的。
一个组件可以将本组件的state传递到该组件的子组件中,并作为子组件的一个props
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
比如这里的我们将this.state.data.toLocaleTimeString()这个当前<h2>组件的state传入到其子组件,并作为其props
下面的例子应该更加可以说明这个问题

<FormattedDate date={this.state.date} />
function FormattedDate(props) {
  return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值