React+TypeScript调用Rest Countries API获取嵌套数据报错求助
解决Rest Countries API中语言和货币的渲染问题
你的问题出在两个核心点:接口类型定义错误,以及嵌套数据的访问方式不对。以下是具体修正步骤:
1. 修正TypeScript接口定义
Rest Countries API返回的languages和currencies是键值对对象,不是数组;另外capital、timezones是数组,borders可能为空。更新接口:
interface Country { name: { common: string; official: string; }; capital?: string[]; flags: { svg: string; }; region: string; languages?: { [code: string]: string }; currencies?: { [code: string]: { name: string; symbol: string } }; timezones: string[]; borders?: string[]; }
2. 修正State类型
不要用any[],明确指定类型:
const [country, setCountry] = useState<Country[]>([]);
3. 正确渲染嵌套数据
针对语言、货币、时区、首都和边境,处理空值并正确访问嵌套内容:
- 语言:用
Object.values提取所有语言名称,再拼接 - 货币:遍历货币对象,提取名称和符号后拼接
- 其他字段:处理可能为空的情况,避免报错
完整修正后的代码
import { useParams } from "react-router-dom"; import { useState, useEffect } from "react"; import axios from "axios"; const Country = () => { interface Country { name: { common: string; official: string; }; capital?: string[]; flags: { svg: string; }; region: string; languages?: { [code: string]: string }; currencies?: { [code: string]: { name: string; symbol: string } }; timezones: string[]; borders?: string[]; } const { id } = useParams(); const [country, setCountry] = useState<Country[]>([]); const [isLoading, setLoading] = useState<boolean>(false); const [isError, setError] = useState<any>(null); useEffect(() => { const singleData = async () => { try { setLoading(true); const response = await axios.get( `https://restcountries.com/v3.1/name/${id}`, ); setCountry(response.data); } catch (err) { console.log(err); setError(err); } finally { setLoading(false); } }; singleData(); }, [id]); return ( <div className='w-full h-screen p-4 flex justify-center items-center'> {isLoading && <p className='text-xl font-medium'>...Loading</p>} {isError && ( <p className='text-xl font-medium'>Error loading country details </p> )} {country.map((countryItem: Country, key: number) => ( <div key={key} className='w-4/5 rounded-2xl h-2/3 flex bg-slate-900 p-4 gap-4 text-slate-200 '> <div className='w-4/5 flex justify-center items-center'> <img className='w-fit h-70 object-contain' src={countryItem.flags.svg} alt={`${countryItem.name.common} flag`} /> </div> <div className='w-full h-full p-4'> <ul className='list-none text-xl'> <li> Name: {countryItem.name.common}</li> <li> Official Name: {countryItem.name.official}</li> <li> Capital: {countryItem.capital ? countryItem.capital.join(", ") : "N/A"}</li> <li> Region: {countryItem.region}</li> <li> Languages: {countryItem.languages ? Object.values(countryItem.languages).join(", ") : "N/A"}</li> <li> Currencies: {countryItem.currencies ? Object.values(countryItem.currencies).map(curr => `${curr.name} (${curr.symbol})`).join(", ") : "N/A"}</li> <li> Timezone: {countryItem.timezones.join(", ")}</li> <li> Border: {countryItem.borders ? countryItem.borders.join(", ") : "N/A"}</li> </ul> </div> </div> ))} </div> ); }; export default Country;
关键说明
- 把原接口里的
languages: []和currencies: []改成对象类型,匹配API返回结构 - 渲染时用
Object.values()提取对象中的值,避免直接访问不存在的name属性 - 对所有可能为空的字段(如capital、borders)增加空值判断,防止页面报错
内容的提问来源于stack exchange,提问作者clemon ezeh
相关产品推荐
相关产品推荐

