You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript-React问题:Todo数组无法作为组件渲染显示

TypeScript-React中接口获取的Todo数组无法渲染问题修复

问题现象

调用接口获取的Todo数组无法在组件中渲染,但打印日志或查看React元素时能看到正确数据。

核心问题分析

  1. 异步时序错误:getTodos是异步请求,setTodos(_todos)在请求完成前就执行,此时_todos还是空数组。
  2. 状态存储不当:直接将React元素存入state,违背React状态管理最佳实践,应存储原始数据,渲染时再生成组件。
  3. Key值不规范:使用全局counter作为组件key,易导致重复或不必要的重渲染,不符合React key的要求。
  4. 类型定义缺失:接口返回数据和state缺少明确的TypeScript类型定义,易引发隐性错误。
  5. 定时器未清理:useEffect中的setInterval未清理,会造成内存泄漏。
  6. 布尔值判断错误:接口返回的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 09:45:40