欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

React State and Lifecycle

程序员文章站 2022-03-16 17:17:22
...

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
    );
  }

通过以上步骤的改造,效果图如下
React State and Lifecycle
再次快速回顾下

  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>;
}
相关标签: react