React

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > React > React State

React State与生命周期详细介绍

作者:小绵杨Yancy

React将组件(component)看成一个状态机(State Machines),通过其内部自定义的状态(State)和生命周期(Lifecycle)实现并与用户交互,维持组件的不同状态

一、State

在React当中,当你更新组件的state,然后新的state就会重新渲染到页面中。在这个时候不需要你操作任何DOM。这和vue中组件的data中的数据是相似的。

1.1 类组件中的State

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>State</title>
    <script src="https://cdn.staticfile.org/react/16.8.0/umd/react.development.js"></script>
    <script src="https://cdn.staticfile.org/react-dom/16.8.0/umd/react-dom.development.js"></script>
    <!-- 生产环境中不建议使用 -->
    <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
  </head>
  <body>
    <div id="app"></div>
    <script type="text/babel">
      class Clock extends React.Component {
        constructor(props) {
          super(props);
          this.state = { title: "React State", date: new Date() };
          this.handleClick = this.handleClick.bind(this);
        }
        handleClick() {
          this.setState({ date: new Date() });
        }
        render() {
          return (
            <div>
              <p>{this.state.title}</p>
              <p>现在是 {this.state.date.toLocaleTimeString()}.</p>
              <button onClick={this.handleClick}>更新时间</button>
            </div>
          );
        }
      }
      ReactDOM.render(<Clock />, document.getElementById("app"));
    </script>
  </body>
</html>

类组件需要在constructor中定义this.state对象,其对应的属性就是需要使用的state,例如上面代码中的title和date属性,在render函数中通过this.sate.XXX调用。

注意,修改state需要调用this.setState方法,不可以直接对state进行赋值。

这里的handleClick是按钮的点击事件,点击按钮后,调用setState方法重新为date赋值,此时页面会自动更新。

1.2 函数组件中的State

函数组件没有state => React v16.8.0推出Hooks API,其中的一个API叫做useState可以解决问题。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>State</title>
    <script src="https://cdn.staticfile.org/react/16.8.0/umd/react.development.js"></script>
    <script src="https://cdn.staticfile.org/react-dom/16.8.0/umd/react-dom.development.js"></script>
    <!-- 生产环境中不建议使用 -->
    <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
  </head>
  <body>
    <div id="app"></div>
    <script type="text/babel">
      const Clock = (props) => {
        const [n, setN] = React.useState(0);
        function addNum() {
          setN(n + 1);
        }
        return (
          <div>
            <p>现在的n是 {n} .</p>
            <button onClick={addNum}>n+1</button>
          </div>
        );
      };
      ReactDOM.render(<Clock />, document.getElementById("app"));
    </script>
  </body>
</html>

可以看到,在函数组件中使用state需要借助useState,并且useState会返回setXXX方法用于修改定义的state,相比于类组件,函数组件更加简洁,而且不用关注修改state时的this指向问题。

二、React生命周期

组件的生命周期可分成三个状态:

2.1 挂载

当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下:

  1. constructor(): 在 React 组件挂载之前,会调用它的构造函数。
  2. getDerivedStateFromProps():在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。
  3. render(): render() 方法是 class组件中唯一必须实现的方法。
  4. componentDidMount(): 在组件挂载后(插入 DOM 树中)立即调用。

render() 方法是 class 组件中唯一必须实现的方法,其他方法可以根据自己的需要来实现。

2.2 更新

每当组件的 state 或 props 发生变化时,组件就会更新。

当组件的 props 或 state 发生变化时会触发更新。组件更新的生命周期调用顺序如下:

  1. getDerivedStateFromProps(): 在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。根据shouldComponentUpdate() 的返回值,判断 React 组件的输出是否受当前 state 或 props更改的影响。
  2. shouldComponentUpdate():当 props 或 state 发生变化时,shouldComponentUpdate() 会在渲染执行之前被调用。
  3. render(): render() 方法是 class 组件中唯一必须实现的方法。
  4. getSnapshotBeforeUpdate(): 在最近一次渲染输出(提交到 DOM节点)之前调用。
  5. componentDidUpdate(): 在更新后会被立即调用。

render() 方法是 class 组件中唯一必须实现的方法,其他方法可以根据自己的需要来实现。

2.3 卸载

当组件从 DOM 中移除时会调用如下方法:

componentWillUnmount(): 在组件卸载及销毁之前直接调用。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Lifecycle</title>
    <script src="https://cdn.staticfile.org/react/16.8.0/umd/react.development.js"></script>
    <script src="https://cdn.staticfile.org/react-dom/16.8.0/umd/react-dom.development.js"></script>
    <!-- 生产环境中不建议使用 -->
    <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
  </head>
  <body>
    <div id="app"></div>
    <script type="text/babel">
      class Button extends React.Component {
        constructor(props) {
          super(props);
          this.state = { data: 0 };
          this.setNewNumber = this.setNewNumber.bind(this);
        }
        setNewNumber() {
          this.setState({ data: this.state.data + 1 });
        }
        render() {
          return (
            <div>
              <button onClick={this.setNewNumber}>INCREMENT</button>
              <Content myNumber={this.state.data}></Content>
            </div>
          );
        }
      }
      class Content extends React.Component {
        componentWillMount() {
          console.log("Component WILL MOUNT!");
        }
        componentDidMount() {
          console.log("Component DID MOUNT!");
        }
        componentWillReceiveProps(newProps) {
          console.log("Component WILL RECEIVE PROPS!");
        }
        shouldComponentUpdate(newProps, newState) {
          return true;
        }
        componentWillUpdate(nextProps, nextState) {
          console.log("Component WILL UPDATE!");
        }
        componentDidUpdate(prevProps, prevState) {
          console.log("Component DID UPDATE!");
        }
        componentWillUnmount() {
          console.log("Component WILL UNMOUNT!");
        }
        render() {
          return (
            <div>
              <h3>{this.props.myNumber}</h3>
            </div>
          );
        }
      }
      ReactDOM.render(
        <div>
          <Button />
        </div>,
        document.getElementById("app")
      );
    </script>
  </body>
</html>

注意:只有类组件才有生命周期。函数组件每次都是重新运行函数,旧的组件即刻被销毁。

2.4 函数式组件useEffect

与使用state需要借助useState一样,在函数组件中,我们需要借助可以借助react提供的方法在函数式组件中实现“生命周期”,它就是useEffect

useEffect 给函数组件增加了操作副作用的能力。它跟 class 组件中的

componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的用途,只不过被合并成了一个 API。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>useEffect</title>
    <script src="https://cdn.staticfile.org/react/16.8.0/umd/react.development.js"></script>
    <script src="https://cdn.staticfile.org/react-dom/16.8.0/umd/react-dom.development.js"></script>
    <!-- 生产环境中不建议使用 -->
    <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
  </head>
  <body>
    <div id="app"></div>
    <script type="text/babel">
      const Clock = (props) => {
        const [n, setN] = React.useState(0);
        function addNum() {
          setN(n + 1);
        }
        React.useEffect(() => {
          console.log(n);
        });
        return (
          <div>
            <p>现在的n是 {n} .</p>
            <button onClick={addNum}>n+1</button>
          </div>
        );
      };
      ReactDOM.render(<Clock />, document.getElementById("app"));
    </script>
  </body>
</html>

可以看到,上面的使用useEffect时,挂载或者销毁时,都会触发useEffect中的函数,那么如何使用useEffect模拟生命周期呢?

//    只在组件挂载后显示,只需要加个空数组做参数即可
    useEffect(() => {
        document.title = `You clicked ${count} times`;
    },[]);
//    销毁阶段
    useEffect(() => {
        return ()=>{
				console.log("销毁阶段")
			}
    });

三、总结

可以看到,类组件和函数组件在State和生命周期上区别还是非常大的,函数式组件需要调用react提供的hooks(钩子函数,非常重要,后面会专门学习)来实现类组件对于的功能。

学习过程中,我发现react类组件类似于vue2的选项式api组件,而函数组件则vue3组合式api十分相似。

到此这篇关于React State与生命周期详细介绍的文章就介绍到这了,更多相关React State内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文