![](/img/trans.png)
[英]How do I update Reactjs State with data I retrieved using a fetch API call?
[英]ReactJS: I can not get the state to update with API data when the asynchronous API data fetch is completed
在将状态设置为来自返回的异步API请求的数据之前,渲染组件时遇到了一些问题。 我有一个fetch()
方法,该方法会触发,从API返回数据,然后将状态设置为该数据。 这是处理此问题的代码块:
class App extends Component {
constructor() {
super();
this.state = {
currentPrice: null,
};
}
componentDidMount() {
const getCurrentPrice = () => {
const url = 'https://api.coindesk.com/v1/bpi/currentprice.json';
fetch(url).then(data => data.json())
.then(currentPrice => {
this.setState = ({
currentPrice: currentPrice.bpi.USD.rate
})
console.log('API CALL', currentPrice.bpi.USD.rate);
}).catch((error) => {
console.log(error);
})
}
getCurrentPrice();
}
您会注意到我用来检查API数据是否正在返回的console.log('API CALL', currentPrice.bpi.USD.rate
),并且绝对是。 currentPrice.bpi.USD.rate
在控制台中按预期返回一个整数(例如2345.55
)。
太好了,因此我假设this.setState = ({ currentPrice: currentPrice.bpi.USD.rate })
可以正确设置状态,因为已成功接收到此数据。
现在,我将组件渲染如下:
render() {
return (
<div>
<NavigationBar />
<PriceOverview data={this.state.currentPrice}/>
</div>
);
}
}
export default App;
有了这个,我期望能够像下面这样在PriceOverview.js
组件中访问此数据: this.props.data
我已经使用console.log()
来检查this.props.data
组件中的PriceOverview.js
,并且我得到了“ null”,因为这是我PriceOverview.js
设置的默认值。 我遇到的问题是,组件在API提取运行之前就渲染了,并使用返回的数据更新了状态。 因此,当App.js
渲染PriceOverview.js
组件时,它仅将currentPrice: null
传递给它,因为异步fetch()
尚未在渲染之前返回数据。
我的困惑在于this.setState
。 我已经读过, this.setState
被调用,React就会调用render。 因此,在我看来,一旦fetch()
请求返回,它将调用this.setState
并将状态更改为返回的数据。 反过来,这将导致重新渲染,并且新的状态数据应该可用。 如果我不说我在这里感到困惑,那我会撒谎。 我假设一旦fetch()
返回,它将使用请求的数据更新状态,然后触发重新渲染。
这里肯定有我想念的东西,但是我的经验不足让我一个人..冷..在绝望的黑暗中。 我在使用“硬编码”数据时没有问题,因为我可以很好地传递数据而不必担心数据何时返回。 例如,如果我将App.js中的状态设置为this.state = { currentPrice: [254.55] }
,则可以通过零问题通过this.props.data
在PriceOverview.js
访问它。 是异步API请求将我带到了这里,恐怕今晚它已成为我的最佳选择。
此处完整显示了App.js:
import React, { Component } from 'react';
import './components/css/App.css';
import NavigationBar from './components/NavigationBar';
import PriceOverview from './components/PriceOverview';
class App extends Component {
constructor() {
super();
this.state = {
currentPrice: null,
};
}
componentDidMount() {
const getCurrentPrice = () => {
const url = 'https://api.coindesk.com/v1/bpi/currentprice.json';
fetch(url).then(data => data.json())
.then(currentPrice => {
this.setState = ({
currentPrice: currentPrice.bpi.USD.rate
})
console.log('API CALL', currentPrice.bpi);
}).catch((error) => {
console.log(error);
})
}
getCurrentPrice();
}
render() {
return (
<div>
<NavigationBar />
<PriceOverview data={this.state.currentPrice}/>
</div>
);
}
}
export default App;
这是完整的PriceOverview.js:
import React, { Component } from 'react';
import './css/PriceOverview.css';
import bitcoinLogo from './assets/bitcoin.svg';
class PriceOverview extends Component {
constructor(props) {
super(props);
this.state = {
currentPrice: this.props.data
}
}
render() {
return (
<div className="overviewBar">
<div className="currentPrice panel">
{ this.state.currentPrice != null ? <div className="price">{this.state.currentPrice}</div> : <div className="price">Loading...</div> }
</div>
</div>
)
}
}
export default PriceOverview;
预先感谢您的任何帮助,非常感谢。
问题是任何JS类的构造函数都只能调用一次。 每当您调用this.setState
时,就会调用render
方法。
因此,基本上,您是在构造函数中一次将currentPrice
设置为null
,然后使用state访问它,因此它将始终为null。
更好的方法是使用道具。
您可以在PriceOverview.js
执行类似的PriceOverview.js
。
import React, { Component } from 'react';
import './css/PriceOverview.css';
import bitcoinLogo from './assets/bitcoin.svg';
class PriceOverview extends Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return (
<div className="overviewBar">
<div className="currentPrice panel">
{ this.props.data!= null ? <div className="price">{this.props.data}</div> : <div className="price">Loading...</div> }
</div>
</div>
)
}
}
export default PriceOverview;
或者,您可以使用PriceOverview.js
生命周期方法componentWillReceiveProps
来更新PriceOverview.js
的状态
componentWillReceiveProps(nextProps) {
this.setState({
currentPrice:nextProps.data
});
}
render() {
return (
<div className="overviewBar">
<div className="currentPrice panel">
{ this.state.currentPrice != null ? <div className="price">{this.state.currentPrice }</div> : <div className="price">Loading...</div> }
</div>
</div>
)
}
}
好的,第一件事,当您在React上编写代码时,保持状态的组件是类的基础组件,所以...我在这里看到的是您正在创建两个类的基础组件,因此当您从应用程序类传递props时到PriceOverview的组件是另一个基本类组件,您实际上什么都不做...因为当您在PriceOverview上的构造函数被调用时,您正在该Component和先前的状态上创建一个新状态(这就是您想要的状态)传递)被覆盖,这就是为什么当您要显示它时您似乎为空。 因此,只要将PriveOverview组件更改为基于函数的组件(或哑组件),它就可以工作。 这样,当您通过道具传递状态时,就可以在div中显示正确的状态。 这是什么样子。
import React from 'react';
import './css/PriceOverview.css';
import bitcoinLogo from './assets/bitcoin.svg';
const PriceOverview = (data) => {
return (
<div className="overviewBar">
<div className="currentPrice panel">
//Im calling data here because that's the name you gave it as ref
//No need to use 'this.props' you only use that to pass down props
{data != null ? <div className="price">
{data}</div> : <div className="price">Loading...</div>
}
</div>
</div>
)
}
}
export default PriceOverview;
每当您编写新组件时,如果您的组件只是在其中返回标记,则始终从函数基础组件开始,并且您需要将一些数据传递给其父组件以对其进行更新(在其中进行api调用或在其中设置状态)并传递按下要通过ref渲染的道具。 尽可能多地阅读React文档,希望这个解释有用(如果您不太了解我的道歉,因为我的语法我必须努力解决)
this.setState ({
currentPrice: currentPrice.bpi.USD.rate
})
不要在this.setState
中this.setState
=
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.