[React 基础系列] 状态 & 状态更新 & 生命周期方法

Posted GoldenaArcher

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[React 基础系列] 状态 & 状态更新 & 生命周期方法相关的知识,希望对你有一定的参考价值。

这一期复习一下 状态(state) 和 生命周期(lifecycle),这一节主要针对的内容是 类组件 中的状态与生命周期,钩子函数(hooks) 中的实现会放在 hooks 中学习。

通过这章的学习,你应该能学会:

  • 如何设置状态
  • 如何 this.setState() 更新状态
  • 常用的几个生命周期方法

之前复习过的内容有:

学习案例下载地址:
[React 基础系列] 状态 & 状态更新 & 生命周期方法-案例

状态

状态(state) 可以用来存放控制组件内的数据变化的变量,如表单内的值就可以存放在状态中去管理。以业务中比较常见的表单逻辑为例,表单中的输入值就很适合放到状态中去管理。

下面模拟一个电话号码为 1301301300 的组件:

class Input extends Component {
  state = {
    input: '13001301300',
  };

  render() {
    return (
      <div>
        <label>{this.props.label}</label>
        <input type="text" value={this.state.input} />
      </div>
    );
  }
}

ReactDOM.render(
  <div className="inputs">
    <Input label="电话" />
  </div>,
  document.getElementById('root')
);

页面的渲染效果看起来如下:

复习一下 props 的相关知识,this.props.label 的值来自于 <Input label="电话" /> 中的 label,是在调用时从父组件传到子组件的参数,值是不可变的。

现在最基础的一个表单组件已经写好了,只是现在这个情况下,因为没有实现对应的事件监听函数,所以,state 中的值是无法被改变的:

同时,打开浏览器的 console 也会出现下列的报错信息,提示要么添加事件管理,要么将 input中的 value 改成 defaultValue,或者将值设为只读属性:

下一步,就通过添加事件去实现对状态的修改,再去简略的讲一下生命周期机制。

状态更新 - onChange

这里会通过绑定时间的方式去更新状态,更新状态的实现是通过 React 内置的函数:this.setState() 去实现的。这里只是简单的调用一下事件,更复杂的内容会单独拉出来讲。

事件机制的实现如下:

class Input extends Component {
  // state 部分不变

  // 添加 event handler
  updateInputHandler = (e) => {
    this.setState({
      input: e.target.value,
    });
  };

  // 更新render,主要给 input 添加 onChange
  render() {
    return (
      <div>
        <label>{this.props.label}</label>
        <input
          type="text"
          value={this.state.input}
          // 新增代码
          onChange={(e) => this.updateInputHandler(e)}
        />
      </div>
    );
  }
}

实现 handler 后即可更新状态:

onChange={(e) => this.updateInputHandler(e)} 这样的写法是利用了箭头函数简短和不重写 this指向 的特性,同时将 event 对象传入到函数中去,并且不会出现立即执行的问题。

在实现了状态更新后,就可以联系一个与状态更新有关的生命周期方法——componentDidUpdate。

注*:React 的设计理念是状态的不可变性,所以默认所有的状态变更,包括捕获状态变更都是通过 this.setState 去实现的。如果直接修改状态不会触发其他生命周期函数——包括 render——的调用。render 如果不被调用,就不会页面的重新渲染。

生命周期方法

下面列举的生命周期方法,相对而言使用的比较频繁的生命周期函数。另外,生命周期函数的调用 不能 使用箭头函数。

constructor

也就是构造函数,通常用来初始化状态以及触发一些副作用(调用其他的函数)。如果不需要在构造函数内触发副作用,只需要初始化状态的情况下,也可以直接通过申明的方法去实现,如:

state = {
  input: '13001301300',
};

上面的代码在构造函数内实现,是这样的写法:

class Input extends Component {
  // 必须要传入 props 参数
  constructor(props) {
    // 也必须要调用 super(props)
    super(props);
    this.state = { input: '13001301300' };
  }
}

注,不调用 super(props); 会产生报错:

render

render 也是生命周期函数,它负责渲染整个页面。

页面在挂在过程中,调用完了 constructor 去初始化状态后,就会调用 render 去渲染页面。

componentDidUpdate

在函数更新是调用,这里可以通过参数显示之前的 props、state 和 snapshot,同时也可以通过 this 关键字获取当前的 props 和 state。

这个函数经常会被用来触发副作用,例如说当状态从未登录改为登录是,就可以在 componentDidUpdate 中去调用其他的 API:如获取用户信息、获取登陆用户才能够访问的信息,等。

这里就通过在命令行输出展示一下 componentDidUpdate 的使用方法,代码如下:

class Input extends Component {
  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log('prevProps', prevProps, 'curr props', this.props);
    console.log('prevState', prevState, 'curr state', this.state);
  }
}

触发效果如下:

可以看到,prevPropscurr props 的值是一样的,但是每次当值变更过后,prevStatecurr state 的值是由差异的。这个差异就是由状态更新而产生的,prevState 的值是这次更新前的状态,curr state 是更新后的状态。

componentDidUpdate 中也可以通过调用 this.setState() 去触发其他的状态变化,但是需要注意的一点是,在 componentDidUpdate 中触发状态变化一定要注意判断,否则就有可能会产生无限更新,从而导致程序崩溃,如:

class Input extends Component {
  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log('prevProps', prevProps, 'curr props', this.props);
    console.log('prevState', prevState, 'curr state', this.state);
    // 每次状态更新都会形成一个新的对象,所以 prevState 和 this.state 永远不会想等
    if (prevState !== this.state) {
      this.setState({ input: '' });
    }
  }
}

就会导致无限更新的问题:

componentDidMount

componentDidMount 是一个使用频率也很高的函数,它在页面挂载之后就会立刻被调用,可以在 componentDidMount 函数中触发副作用,即,调用 API 去更新状态。

这里会在 componentDidMount 中调用 setTimeout 去模拟 API 调用发生的延迟状态,随后在 setTimeout 中进行状态更新。

class Input extends Component {
  componentDidMount() {
    setTimeout(() => {
      this.setState({
        input: '1357924680',
      });
    }, 3000);
  }
}

在页面渲染(这里就是页面被刷新,模拟一下刚刚打开页面的情况)之后,componentDidMount 会立刻被调用,随后大概在 3 秒中后,电话号码就会从 13001301300 变成 1357924680

总结

这章内容主要讲了如何初始化以及在不同的情况下去更新状态,同时简单的讲了一下几个常见的生命周期方法,以及生命周期方法的使用场景。

通过完成这一部分的学习,已经可以实现简单的业务功能了。

以上是关于[React 基础系列] 状态 & 状态更新 & 生命周期方法的主要内容,如果未能解决你的问题,请参考以下文章

React 系列导航

[React 基础系列] React Router 的基本应用

React基础篇 -- state&props&refs

前端一个更底层库-React基础知识

[React 基础系列] 受控表单 vs 不受控表单

2-2-4 & 5 & 6 React Hooks基础API