我有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中将获取选项并设置默认值。
谢谢。
答案 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;