[英]How to update state inside componentDidMount?
I'm using fetch API and I want update the const called state inside the componentDidMount() (with onChange) which are being using in a template string. 我正在使用fetch API,并且我想在componentDidMount()(使用onChange)中更新正在模板字符串中使用的const状态。 How do I update this value with onChange?
如何使用onChange更新此值?
import React, {Component} from 'react'
class Data extends Component {
constructor() {
super();
this.state = {
items: {},
value: '',
isLoaded: false
}
}
handleChange(e) {
this.setState({value: e.target.value});
}
componentDidMount() {
const state = this.state.value
fetch(`http://api.timezonedb.com/v2.1/get-time-zone?key=J9X3EOT2EM8U&format=json&by=zone&zone=${state}`)
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
items: json,
})
});
}
render(){
const {isLoaded} = this.state;
if(!isLoaded) {
return <div>Loading...</div>
}
return(
<div>
<select onChange={this.handleChange}>
<option value="America/Chicago">Chicago</option>
<option value="America/Sao_Paulo">São Paulo</option>
</select>
</div>
)
}
}
So, how can I update the value of the const state with onChange? 那么,如何使用onChange更新const状态的值?
componentDidMount()
is called when the React component has mounted, and it happens only once. 安装React组件时会调用
componentDidMount()
,并且它只会发生一次。
If I understand correctly, you want to call fetch
on each change of the value stored under value
state property, so the componentDidMount
method is not a perfect place to put that kind of logic. 如果我理解正确,您想对存储在
value
状态属性下的value
每次更改调用fetch
,因此componentDidMount
方法不是放置这种逻辑的理想场所。 You can create a separate method called fetchData
and pass the value to it as an argument. 您可以创建一个名为
fetchData
的单独方法,并将该值作为参数传递给它。 Then you can call that method on componentDidMount
as well as on each value property change (in our case - onChange
event). 然后,您可以在
componentDidMount
以及每个值属性更改(在我们的情况下为onChange
事件)中调用该方法。
import React, { Component } from "react"; class Data extends Component { constructor(props) { super(props); this.state = { items: {}, value: "America/Chicago", isLoaded: false }; this.handleChange = this.handleChange.bind(this); } componentDidMount() { const { value } = this.state; this.fetchData(value); } handleChange(event) { const value = event.target.value; this.setState({ value }); this.fetchData(value); } render() { const { isLoaded, value, items } = this.state; if (!isLoaded) { return <div>Loading...</div>; } return ( <div> <select onChange={this.handleChange} value={value}> <option value="America/Chicago">Chicago</option> <option value="America/Sao_Paulo">São Paulo</option> </select> {JSON.stringify(items)} </div> ); } fetchData(value) { fetch( `https://api.timezonedb.com/v2.1/get-time-zone?key=J9X3EOT2EM8U&format=json&by=zone&zone=${value}` ) .then(res => res.json()) .then(json => { this.setState({ isLoaded: true, items: json }); }); } }
Working demo: https://codesandbox.io/embed/728jnjprmq 工作演示: https : //codesandbox.io/embed/728jnjprmq
Tomasz's code has 2 mistakes: (1) it fetches resources w/o checking if the component has been unmounted; Tomasz的代码有2个错误:(1)不获取组件是否已卸载而获取资源。 (2) it starts the request w/o updating the UI first.
(2)它首先启动不更新UI的请求。
I would do the following instead: 我将改为执行以下操作:
import React, {Component} from 'react'
class Data extends Component {
constructor() {
super();
this.state = {
items: {},
value: '',
isLoaded: false
}
this._isMounted = false;
// don't forget to bind your methods
this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
this._isMounted = true;
}
componentWillUnmount() {
this._isMounted = false;
}
handleChange(e) {
const value = e.target.value;
this.setState({ value }, () => {
if (!this._isMounted) return;
const url = `http://api.timezonedb.com/v2.1/get-time-zone?key=J9X3EOT2EM8U&format=json&by=zone&zone=${value}`
fetch(url).then((res) => {
if (!this._isMounted) return;
const data = res.json();
this.setState({ isLoaded: true, items: data });
})
});
}
render(){
const { isLoaded } = this.state;
if(!isLoaded) {
return <div>Loading...</div>
}
return(
<div>
<select onChange={this.handleChange}>
<option value="America/Chicago">Chicago</option>
<option value="America/Sao_Paulo">São Paulo</option>
</select>
</div>
)
}
}
Assuming you want to refresh the value of this.state.items
when the user changes the value of the select
, you can do this in the onChange
. 假设您要在用户更改
select
的值时刷新this.state.items
的值,则可以在onChange
执行此操作。 However, your code is in a few (incorrect) pieces. 但是,您的代码有几段(不正确)。 Let's start from the top.
让我们从头开始。
First of all, you're setting the value
property of state
to ''
, so your componentDidMount
function is going to see that value. 首先,将
state
的value
属性设置为''
,因此componentDidMount
函数将看到该值。 I assume that's no good, so let's strip that out of componentDidMount
entirely. 我认为那不好,所以让我们将其完全从
componentDidMount
中删除。 We can move this code to the handleChange
function instead, but it'll still need to be changed: 我们可以将这段代码移到
handleChange
函数中,但是仍然需要更改它:
handleChange(e) {
this.setState({value: e.target.value});
fetch(`http://api.timezonedb.com/v2.1/get-time-zone?key=J9X3EOT2EM8U&format=json&by=zone&zone=${e.target.value}`)
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
items: json,
})
});
}
Notice my change - we can't access the value from the state, because setState
is asynchronous, and so the value hasn't been updated by this point. 注意我的更改-我们无法从状态访问值,因为
setState
是异步的,因此此时尚未更新值。 We know the value comes from the select
though. 我们知道价值来自
select
。
The other thing you could do to improve this functionality is to turn the select
into a controlled component. 改善此功能的另一件事是将
select
变成受控组件。 To do this, you just have to set the value of the field to be controlled by the state of this component. 为此,您只需要设置要由该组件的状态控制的字段的值即可。 Since you're using an
onChange
listener for this, it makes the field a controlled component (if you weren't using an onChange, it would be a read-only field. 由于您为此使用了
onChange
侦听器,因此它使该字段成为受控组件(如果您不使用onChange,则它将是一个只读字段。
The loading
variable in state
appears to be being used incorrectly, I'm guessing you just need to check if there's data in 'items'. state
中的loading
变量似乎未正确使用,我猜您只需要检查'items'中是否有数据。 I'll remove this for now, but you could come back to this. 我现在将其删除,但是您可以回到此位置。
render(){
const {isLoaded} = this.state;
if(!isLoaded) {
return <div>Loading...</div>
}
return(
<div>
<select onChange={this.handleChange}>
<option value="America/Chicago">Chicago</option>
<option value="America/Sao_Paulo">São Paulo</option>
</select>
</div>
)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.