TypeScript-React问题:Todo数组无法作为组件渲染显示
TypeScript-React中接口获取的Todo数组无法渲染问题修复
问题现象
调用接口获取的Todo数组无法在组件中渲染,但打印日志或查看React元素时能看到正确数据。
核心问题分析
- 异步时序错误:
getTodos是异步请求,setTodos(_todos)在请求完成前就执行,此时_todos还是空数组。 - 状态存储不当:直接将React元素存入state,违背React状态管理最佳实践,应存储原始数据,渲染时再生成组件。
- Key值不规范:使用全局
counter作为组件key,易导致重复或不必要的重渲染,不符合React key的要求。 - 类型定义缺失:接口返回数据和state缺少明确的TypeScript类型定义,易引发隐性错误。
- 定时器未清理:
useEffect中的setInterval未清理,会造成内存泄漏。 - 布尔值判断错误:接口返回的
done是布尔类型,却用todo["done"] === "true"判断,导致值判断错误。
修复步骤及代码示例
1. 定义Todo类型,完善API类型
修改todoApi.ts,添加明确的TypeScript类型:
import axios, { AxiosResponse } from "axios"; // 定义Todo类型 export interface Todo { id: number; name: string; description: string; done: boolean; dateCreated: string; deadline: string; } const API_URL: string = "http://localhost:8080/api/v1/todo/"; export async function getTodos(filter: string): Promise<Todo[]> { const response: AxiosResponse<Todo[]> = await axios.get(API_URL, { headers: { filter: filter } }); return response.data; // 无需再await,response.data已是同步值 }
2. 修正App组件的逻辑错误
修改App.tsx,调整异步时序、状态存储方式、key值、定时器清理等:
import { useState, useEffect } from "react"; import { getTodos, Todo } from "../api/todoApi"; import TodoComponent from "./Todo"; // 替换为你的Todo组件实际路径 export default function App(): JSX.Element { // 存储原始Todo数据,而非React元素 const [todos, setTodos] = useState<Todo[]>([]); useEffect(() => { // 定义获取数据的函数 const fetchTodos = async () => { const filter = sessionStorage.getItem("search-key") || ""; const fetchedTodos = await getTodos(filter); setTodos(fetchedTodos); }; // 初始调用一次 fetchTodos(); // 设置定时器,每500ms获取一次数据 const intervalId = setInterval(fetchTodos, 500); // 清理定时器,防止内存泄漏 return () => clearInterval(intervalId); }, []); return ( <> <div id="todos"> {/* 其他组件 */} {/* 渲染时根据原始数据生成Todo组件 */} {todos.map(todo => ( <TodoComponent key={todo.id} // 使用todo的唯一id作为key id={todo.id} name={todo.name} description={todo.description} dateCreated={todo.dateCreated} deadline={todo.deadline} done={todo.done} // 直接使用布尔值 /> ))} {/* 其他组件 */} </div> </> ); }
3. 验证Todo组件的属性接收
确保Todo组件正确接收类型化的属性:
import { Todo } from "../api/todoApi"; // 定义组件属性类型 interface TodoProps extends Todo {} export default function TodoComponent({ id, name, description, dateCreated, deadline, done }: TodoProps) { return ( <div className="todo"> <h1>ID: {id}</h1> <h1>Name: {name}</h1> <h1>Description: {description}</h1> <h1>Created: {dateCreated}</h1> <h1>Deadline: {deadline}</h1> <h1>Done: {done ? "Yes" : "No"}</h1> </div> ); }
关键修复点说明
- 异步时序:将
getTodos的调用放在async函数中,确保请求完成后再更新state。 - 状态存储:只存储原始数据,渲染时通过
map生成组件,符合React状态管理的最佳实践。 - Key值:使用todo的
id作为key,保证唯一性,避免不必要的组件重渲染。 - 类型安全:添加明确的TypeScript类型定义,减少隐性错误。
- 内存泄漏:在
useEffect的返回函数中清理定时器。 - 布尔值判断:直接使用接口返回的布尔类型
done,无需字符串比较。
内容的提问来源于stack exchange,提问作者George Athans
相关产品推荐
相关产品推荐

