React.ts调用食谱API:嵌套对象数组类型定义及展示问题
解决React+TypeScript中嵌套API数据的类型定义问题
问题背景
使用React+TypeScript调用食谱API,能正常获取title、image、summary字段,但无法访问analyzedInstructions里的steps数据,核心问题是嵌套对象数组的TypeScript类型定义错误,同时存在拼写失误。
用户原组件代码
export function RecipeDetails() { const initialRecipeState = { title: '', analizedInstructions: [{ steps: [{ name: '' }] }], image: '', summary: '' } const { id } = useParams(); const [data, setData] = useState<RecipeData>(initialRecipeState); useEffect( () => { const getData = async() => { const newData = await fetchData(`https://api.spoonacular.com/recipes/${id}/information?apiKey=key&includeNutrition=false`) setData(newData) } getData(); console.log(data.analizedInstructions) },[])
用户原类型定义代码
export type RecipeData = { title: string, analizedInstructions: Steps, image: string, summary: string } export type Steps = { name: Name } export type Name = { name: string }
解决方案
1. 修正TypeScript类型定义
根据API返回的结构(analyzedInstructions是数组,每个元素包含steps数组,steps对象包含number、step等字段),重新定义类型:
// 单个步骤的类型,按需添加字段 export type RecipeStep = { number: number; step: string; }; // 单个烹饪说明的类型 export type RecipeInstruction = { name: string; steps: RecipeStep[]; }; // 顶级食谱数据类型 export type RecipeData = { title: string; analyzedInstructions: RecipeInstruction[]; // 明确为数组类型 image: string; summary: string; };
2. 修正组件代码
修正拼写错误,调整初始状态匹配类型,完善逻辑:
export function RecipeDetails() { // 初始状态匹配定义好的类型,修正拼写并设为空数组更合理 const initialRecipeState: RecipeData = { title: '', analyzedInstructions: [], image: '', summary: '' } const { id } = useParams(); const [data, setData] = useState<RecipeData>(initialRecipeState); useEffect(() => { const getData = async () => { if (!id) return; // 避免id为空时请求 const newData = await fetchData(`https://api.spoonacular.com/recipes/${id}/information?apiKey=key&includeNutrition=false`) setData(newData) } getData(); }, [id]) // 添加id作为依赖,id变化时重新请求 // 示例:渲染步骤列表 return ( <div className="recipe-details"> <h1>{data.title}</h1> <img src={data.image} alt={data.title} className="recipe-image" /> {/* summary是HTML字符串,用dangerouslySetInnerHTML渲染 */} <div className="recipe-summary" dangerouslySetInnerHTML={{ __html: data.summary }} /> <section className="recipe-steps"> <h2>制作步骤</h2> {data.analyzedInstructions.map((instruction, idx) => ( <div key={idx} className="instruction-group"> {instruction.name && <h3>{instruction.name}</h3>} <ol> {instruction.steps.map((step) => ( <li key={step.number} className="step-item"> <span className="step-number">{step.number}.</span> {step.step} </li> ))} </ol> </div> ))} </section> </div> ) }
关键修复点
- 拼写修正:将代码中的
analizedInstructions改为analyzedInstructions,与API返回字段名一致,否则无法读取数据。 - 数组类型:
analyzedInstructions是数组类型,类型定义中必须标注为RecipeInstruction[],而非单个对象。 - 依赖优化:给
useEffect添加id依赖项,确保id变化时重新请求数据,同时增加id非空判断避免无效请求。
内容的提问来源于stack exchange,提问作者D_chez12
相关产品推荐
相关产品推荐

