ReactJS - 如何更新嵌套和 "normal" 状态属性?
ReactJS - how do I update nested and "normal" state properties?
这是我的 state
的样子:
constructor(props, context) {
super(props, context);
this.state = {
show: false,
btnLabel: 'GO!',
car: {
owner: false,
manufacturer: false,
color: false
}
};
}
这就是我修改 state
:
的方式
handleClickFetchPrice() {
this.setState({btnLabel: 'Fetching data...' });
console.log(this.state.fetchPriceBtn);
const url = 'some url';
axios.get(url)
.then(res => {
let car = [...this.state.car];
car.owner = res.data.owner;
car.manufacturer = res.data.manufacturer;
car.color = res.data.color;
this.setState({car});
})
}
属性 car
已更新,但 fetchPriceBtn
未更新 - console.log(this.state.fetchPriceBtn);
的输出仍为 GO!
。
我忽略了什么?为什么 fetchPriceBtn
没有更新?
React setState
是一个异步过程——你不知道它什么时候更新,你只能安排更新。
要实现所需的功能,您可以向 setState
方法提供回调。
this.setState({ btnLabel: 'Fetching data...' }, () => console.log(this.state.fetchPriceBtn))
您可以在方法上了解更多following the documentation。
@christopher 是对的,setState
是一个异步过程。但是当第二次调用 handleClickFetchPrice()
函数时,您的 btnLabel
的值将等于 Fetching data...
正如之前答案中的回答,setState 是异步的,因此您的 console.log 无法立即赶上状态变化。再次按照建议,您可以使用回调函数来跟踪此更改,但如果您使用 console.log 只是为了调试或想查看状态的变化,您可以在渲染函数中执行此操作。并且仅仅为了调试而使用回调并不是一个好方法。它的目的有些不同,如果您查看官方文档,建议使用 componentDidMount 方法来实现这种逻辑。
render() {
console.log( this.state.foo );
return (...)
}
如果这样做,您会看到两个 console.log 输出,一个在状态更改之前,一个在状态更改之后。
此外,您的状态操作可能会得到增强。你car属性不是数组,但是你把它转成数组然后设置?这是你想要的吗:
axios.get(url)
.then(res => {
const { owner, manufacturer, color } = res.data;
this.setState( prevState => ( { car: { ...prevState.car, owner, manufacturer, color } } ) );
})
这里我们没有直接改变状态,而是使用扩展运算符并设置所需的属性。对于您的示例,我们实际上设置了整个 属性。
最后一点,我想你想做这样的事情:
this.setState( { btnLabel: "fetching } );
axios.get(url)
.then(res => {
const { owner, manufacturer, color } = res.data;
this.setState( prevState => ( { car: { ...prevState.car, owner, manufacturer, color }, btnLabel: "go" } ) );
})
如果您打算以某种方式执行状态 change/check 这可能不是一个好的逻辑,因为您已经看到 setState 不是同步的。小心操作。
这是我的 state
的样子:
constructor(props, context) {
super(props, context);
this.state = {
show: false,
btnLabel: 'GO!',
car: {
owner: false,
manufacturer: false,
color: false
}
};
}
这就是我修改 state
:
handleClickFetchPrice() {
this.setState({btnLabel: 'Fetching data...' });
console.log(this.state.fetchPriceBtn);
const url = 'some url';
axios.get(url)
.then(res => {
let car = [...this.state.car];
car.owner = res.data.owner;
car.manufacturer = res.data.manufacturer;
car.color = res.data.color;
this.setState({car});
})
}
属性 car
已更新,但 fetchPriceBtn
未更新 - console.log(this.state.fetchPriceBtn);
的输出仍为 GO!
。
我忽略了什么?为什么 fetchPriceBtn
没有更新?
React setState
是一个异步过程——你不知道它什么时候更新,你只能安排更新。
要实现所需的功能,您可以向 setState
方法提供回调。
this.setState({ btnLabel: 'Fetching data...' }, () => console.log(this.state.fetchPriceBtn))
您可以在方法上了解更多following the documentation。
@christopher 是对的,setState
是一个异步过程。但是当第二次调用 handleClickFetchPrice()
函数时,您的 btnLabel
的值将等于 Fetching data...
正如之前答案中的回答,setState 是异步的,因此您的 console.log 无法立即赶上状态变化。再次按照建议,您可以使用回调函数来跟踪此更改,但如果您使用 console.log 只是为了调试或想查看状态的变化,您可以在渲染函数中执行此操作。并且仅仅为了调试而使用回调并不是一个好方法。它的目的有些不同,如果您查看官方文档,建议使用 componentDidMount 方法来实现这种逻辑。
render() {
console.log( this.state.foo );
return (...)
}
如果这样做,您会看到两个 console.log 输出,一个在状态更改之前,一个在状态更改之后。
此外,您的状态操作可能会得到增强。你car属性不是数组,但是你把它转成数组然后设置?这是你想要的吗:
axios.get(url)
.then(res => {
const { owner, manufacturer, color } = res.data;
this.setState( prevState => ( { car: { ...prevState.car, owner, manufacturer, color } } ) );
})
这里我们没有直接改变状态,而是使用扩展运算符并设置所需的属性。对于您的示例,我们实际上设置了整个 属性。
最后一点,我想你想做这样的事情:
this.setState( { btnLabel: "fetching } );
axios.get(url)
.then(res => {
const { owner, manufacturer, color } = res.data;
this.setState( prevState => ( { car: { ...prevState.car, owner, manufacturer, color }, btnLabel: "go" } ) );
})
如果您打算以某种方式执行状态 change/check 这可能不是一个好的逻辑,因为您已经看到 setState 不是同步的。小心操作。