componentDidMount中的ReactJS生命周期setState

时间:2020-07-22 20:37:39

标签: reactjs

我有2个组件来演示我的问题:

父母:

import React from "react";
import ReactDOM from "react-dom";
import { Grid, Row } from "react-flexbox-grid";
import Hello from "./Hello";

class App extends React.Component {
  state = {
    name: "Michal"
  };

  componentDidMount = () => {
    this.setState({ name: "Tina" });
  };

  componentDidUpdate(prevState) {
    console.log("App componentDidUpdate", prevState, this.state);
  }

  handleUpdate = value => {
    console.log("App handleUpdate");
    this.setState({ name: value });
  };

  render() {
    return (
      <Grid>
        <Row>
          <Hello name={this.state.name} update={this.handleUpdate} />
        </Row>
      </Grid>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("container"));

孩子:

import * as React from "react";

class Hello extends React.PureComponent {
  componentDidMount() {
    // setTimeout(() => {
    this.props.update("Matus");
    // }, 0);
  }

  componentDidUpdate(prevProps) {
    console.log("Hello componentDidUpdate", prevProps, this.props);
  }

  render() {
    return <h1>Hello {this.props.name}!</h1>;
  }
}

export default Hello;

在子组件中,我想通过props函数在父状态下设置值。但是setState函数会被忽略,如果从setTimeout调用props函数,它将起作用。

您能解释一下为什么它在setTimeout中起作用,为什么我应该避免这种构造。正确的方法是什么?

Hello组件代表“选择”,它在componentDidMount中将获取选项并设置默认值。

谢谢。

5 个答案:

答案 0 :(得分:3)

组件在React中自下而上初始化。因此,在您的示例中,And match response.group[?(@.name == 'group1')][0] == """ { "name": "group1", "id": #notnull } """ 触发了process.env.NODE_ENV = process.env.NODE_ENV || 'production' const CompressionPlugin = require('compression-webpack-plugin'); const environment = require('./environment') module.exports = environment.toWebpackConfig() module.exports.plugins.push( new CompressionPlugin({ asset: "[path].gz[query]", algorithm: "gzip", test: /\.(js|css)$/, threshold: 10240, minRatio: 0.8 }) ); ,尝试通过Hello在App中设置状态,然后componentDidMount在稍后调用自己的{{ 1}}。您在子组件中设置的名称永远不会到达状态。

我不确定这样做的目的是什么,希望只是出于倾斜的目的,因为组件在安装时不需要立即设置其自身的状态。如果需要在初始化this.props.update中的状态之前执行一些逻辑,则可以使用App并在那里进行。

无论如何,解决方案是删除componentDidMount中的初始状态设置器。

答案 1 :(得分:1)

它不会被忽略并且会触发。您只是没有在日志中观察它。 检出:

https://codesandbox.io/s/kind-jackson-b2r2b?file=/src/App.js

在控制台中,您将在控制台窗口中看到以下执行顺序:

Hello componentDidMount props = Object {name: "Michal", update: function ()}
App handleUpdate value =  Matus 
App componentDidMount props = Object {}
Hello componentDidUpdate props = Object {name: "Tina", update: function ()}
App componentDidUpdate state = Object {}
Object {name: "Tina"}

因此,随着组件从子组件向上完成安装,您将看到子componentDidMount在父组件完成之前触发并完成安装,并触发其componentDidMount

因此,您永远不会观察到进入Matus的状态,因为它会在完成安装时触发Tina的新状态更改。

答案 2 :(得分:1)

由于React生命周期,将忽略Hello组件中的setState函数。基本上,应用componentDidMount函数会在呈现Hello组件之前覆盖其状态更改。这就是setTimeout有帮助的原因,它将状态更改移至新的渲染循环。

我不知道为什么要尝试加载数据并将其从子组件传递给父组件,但是React的一个好习惯是从上到下传递数据。因此,更好的解决方案是使用Select组件仅从父级渲染数据并对用户事件做出反应。

<Select options={options} selected={option} handle={handleSelect} />

答案 3 :(得分:1)

原因:

  • 反应渲染是同步的。
  • 渲染是深度优先遍历

现在

componentDidMount() {
      this.props.update("Matus");
    }

首先执行,设置名称为 Matus 。然后执行以下命令-

componentDidMount = () => { this.setState({ name: "Tina" }); };

这将设置名称 Tina

所有这些都发生在渲染发生的第一个调用堆栈中。如果我们使用 setTimeout(),那么

this.props.update("Matus");

将移至第二个调用堆栈,该堆栈将在初始渲染和安装结束后执行,从而设置名称 Tina 并触发重新渲染。

答案 4 :(得分:-1)

如果要使用类组件,则需要使用构造函数来初始化状态并将道具从父级传递到子级。

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: "Michal"
    };
  }

  // ... rest of parent component
import * as React from "react";

class Hello extends React.PureComponent {
  constructor(props) {
    super(props)
  }

  componentDidMount() {
    // setTimeout(() => {
    this.props.update("Matus");
    // }, 0);
  }

  componentDidUpdate(prevProps) {
    console.log("Hello componentDidUpdate", prevProps, this.props);
  }

  render() {
    return <h1>Hello {this.props.name}!</h1>;
  }
}

export default Hello;