React中Fetch API取数后传递给子组件报错问题排查
Fixing Your React API Data Passing Error
Hey there! I can spot a couple of clear issues that are causing your error when passing API data to the SmallBox component. Let's break them down and fix your code step by step:
Key Problems Identified
- Wrong Initial State Type: You initialized
smallDataas an empty object{}, but the CoinGecko API returns an array of coin objects. When your component first renders, trying to accesssmallData[0].namefails because objects don't have index-based properties like0. - Missing useEffect Dependency Array: Your
useEffectdoesn't have a dependency array, so it runs every single time your component re-renders—spamming the API with infinite requests and causing unnecessary re-renders. - No Loading State Handling: Before the API request finishes,
smallDatais still empty, so accessing properties onsmallData[0]/smallData[1]etc. throws a "Cannot read properties of undefined" error.
Fixed Code
import React, { useState, useEffect } from 'react'; import SmallBox from './SmallBox'; import './App.css'; function App() { // Initialize as empty array to match the API's response structure const [smallData, setSmallData] = useState([]); // Add loading state to handle pending API requests const [isLoading, setIsLoading] = useState(true); useEffect(() => { fetch(`https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=100&page=1&sparkline=false`) .then(response => { // Add validation for failed requests if (!response.ok) { throw new Error('Failed to fetch coin data'); } return response.json(); }) .then(data => { setSmallData(data); setIsLoading(false); }) .catch(error => { console.error('Error fetching data:', error); setIsLoading(false); }); }, []); // Empty array ensures this runs only once on component mount // Show loading message while data is being fetched if (isLoading) { return <div className="app">Loading coin data...</div>; } // Handle edge case where API returns no data if (smallData.length === 0) { return <div className="app">No coin data available</div>; } return ( <div className="app"> {/* Optional chaining (?.) adds an extra safety layer even after our checks */} <SmallBox className="bitcoin" title={smallData[0]?.name}/> <SmallBox className="ethereum" title={smallData[1]?.name}/> <SmallBox className="ripple" title={smallData[2]?.name}/> <SmallBox className="tether" title={smallData[3]?.name}/> </div> ); } export default App;
What Changed & Why?
- Initial State Adjustment: Switched
smallDatafrom{}to[]to align with the array format returned by the API, so index access works once data loads. - useEffect Dependency Array: Added
[]to ensure the API call only runs when the component first mounts, eliminating infinite loops. - Loading State: Added
isLoadingto prevent renderingSmallBoxcomponents until data is ready, stopping the "undefined property" error. - Error Handling: Added
.catch()and response validation to gracefully handle failed API requests instead of letting the app crash. - Optional Chaining: Used
?.as a fallback in case the API returns fewer than 4 coins, adding an extra layer of robustness.
内容的提问来源于stack exchange,提问作者Owen Osagiede
相关产品推荐
相关产品推荐

