[英]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.