React项目中实现双层JSON接口调用的技术求助
Hey there! I see you're stuck trying to make that second API call to fetch detailed coin info after getting the initial list. Let's break down what's going wrong with your current approach and fix it properly.
What's Wrong with Your Attempt
First off, putting API calls inside the render method is a big no-no. Here's why:
renderis a pure function meant only for calculating what UI to show based on current state/props. Async operations here will break React's rendering cycle, sincerenderdoesn't wait for promises to resolve.- Every time your component re-renders (like when state updates), you'd fire off duplicate API calls—super inefficient and error-prone.
- You also have a
thisbinding issue inside themapcallback, sothis.serverRequestisn't pointing to your component instance correctly.
The Correct Approach
We should handle all the data fetching in componentDidMount (or a dedicated fetch function) instead. After getting the initial coin list, we'll use Promise.all to fetch details for every coin at once, then update the state with all the detailed info once all requests resolve.
Here's the revised code:
var Dashboard = React.createClass({ getInitialState: function(){ return { coinListJson: "json/coinlist.json", coinInfo: [] // We'll store all detailed coin data here } }, componentDidMount: function() { // First fetch the coin list axios.get(this.state.coinListJson) .then(result => { const coinIds = result.data.coins.map(coin => coin.id); // Create an array of API requests for each coin const detailRequests = coinIds.map(id => axios.get(`https://api.coinmarketcap.com/v1/ticker/${id}/?convert=EUR`) ); // Wait for all requests to finish return Promise.all(detailRequests); }) .then(detailResults => { // Format the results to include the data we need const coinInfo = detailResults.map(result => ({ id: result.data[0].id, priceBtc: result.data[0].price_btc, priceEur: result.data[0].price_eur // Bonus: include EUR price too! })); // Update state with the detailed info this.setState({ coinInfo }); }) .catch(error => { // Don't forget to handle errors! console.error("Error fetching data:", error); }); }, componentWillUnmount: function() { // Optional: Clean up any pending requests to avoid memory leaks if (this.serverRequest) { this.serverRequest.cancel(); } }, render: function(){ // If we don't have coin info yet, show a loading message if (this.state.coinInfo.length === 0) { return <div>Loading coin data...</div>; } // Render the list with detailed info return ( <ul> {this.state.coinInfo.map((coin, index) => ( <li key={index}> {coin.id} - BTC Price: {coin.priceBtc} | EUR Price: {coin.priceEur} </li> ))} </ul> ) } }); React.render(<Dashboard/>, document.getElementById('dashboard'));
Key Improvements
- All data fetching in
componentDidMount: This is the standard place for initial data loading in React class components. Promise.all: Lets us wait for all detail requests to complete before updating state, so we don't re-render multiple times for each individual request.- Error handling: Added a
catchblock to log any issues with API calls. - Loading state: Shows a message while data is being fetched, so users know something's happening.
- Cleanup: Optional but recommended—cancels pending requests if the component unmounts before they finish, preventing memory leaks.
Why Your Original Render Attempt Failed
When you tried to call axios.get inside map in render, the promise resolves after render has already finished executing. By the time you try to return the <li> element, React has already rendered the UI, so those elements never show up. Plus, you'd be spamming the API every time the component re-renders, which is bad practice.
This approach should get you up and running with the detailed coin list you need!
内容的提问来源于stack exchange,提问作者Michael Colella

