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

React待办列表开发报错:渲染DisplayTasks时无法更新App组件

解决React中"Cannot update a component while rendering a different component"警告

问题场景

开发React待办列表时,出现以下警告:

App.js:10 Warning: Cannot update a component (App) while rendering a different component (DisplayTasks). To locate the bad setState() call inside DisplayTasks, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
at DisplayTasks (http://localhost:3000/static/js/bundle.js:122:3)
at div
at App (http://localhost:3000/static/js/bundle.js:33:76)

相关组件代码如下:

Textinserter.js(任务输入组件)

// Import React and useState from the 'react' library
import React, { useState } from "react";

// Create a functional component named Textinserter
export default function Textinserter({ tasks, setTasks }) {
  // Initialize state variables using useState hook: tasks and tasksInput
  const [tasksInput, setTasksInput] = useState("");

  // Function to handle changes in the input field
  const handleOnChange = (e) => {
    // Update tasksInput state with the value entered in the input field
    setTasksInput(e.target.value);
  };

  // Function to add a task to the tasks list
  const addTask = () => {
    // Check if the trimmed input is not an empty string
    if (tasksInput.trim() !== "") {
      // Create a new task object with an ID and name
      const newTask = { id: tasks.length + 1, name: tasksInput };

      // Update tasks state using the functional form of setTasks
      setTasks((prevTasks) => [...prevTasks, newTask]);

      // Clear the tasksInput state after adding the task
      setTasksInput("");
    }
  };

  // Return JSX for the component
  return (
    <>
      <div className="mb-3">
        {/* Input field and label */}
        <label htmlFor="exampleInputEmail1" className="form-label">
          Enter The Task
        </label>
        <input
          type="text"
          className="form-control"
          id="exampleInputEmail1"
          aria-describedby="emailHelp"
          onChange={handleOnChange} // Handle input changes with handleOnChange function
          value={tasksInput}
        />
        {/* Button to add a task */}
        <div className="conatiner text-center">
          <button className="btn btn-danger my-3" onClick={addTask}>
            Add Task
          </button>
        </div>
      </div>
    </>
  );
}

DisplayTasks.js(任务展示组件,警告触发源)

import React from "react";

// Component to display tasks
export default function DisplayTasks({ tasks, onDelete }) {
  const deleteTask = (taskId) => {
    // Filter out the task with the matching ID and update tasks array
    const updatedTasks = tasks.filter((task) => task.id !== taskId);
    onDelete(updatedTasks);
  };

  // Styling for the main container
  const myStyle = {
    backgroundColor: "#0D6EFD",
    padding: "15px",
    borderRadius: "10px",
  };

  return (
    <div
      // Conditional styling based on the tasks length
      style={
        tasks.length === 0 ? { ...myStyle, visibility: "hidden" } : myStyle
      }
    >
      {/* Heading for the tasks */}
      <h1 className="text-center text-light mb-4">Today's Tasks</h1>

      {tasks && tasks.length > 0 ? ( // Check if tasks exist and not empty
        <ul className="list-group" style={{ width: "100%" }}>
          {tasks.map((task) => (
            <div
              key={task.id}
              className="d-flex justify-content-between align-items-center"
            >
              {/* Container for each task */}
              <span
                className="d-inline-block w-100 overflow-hidden m-2"
                style={{ borderRadius: "10px" }} // Styling for each task container
              >
                {/* List item for the task */}
                <li className="list-group-item" aria-current="true">
                  {task.name}
                </li>
              </span>
              {/* Button to delete the task */}
              <button className="btn btn-danger" onClick={deleteTask(task.id)}>
                Delete
              </button>
            </div>
          ))}
        </ul>
      ) : (
        // Display if tasks array is empty or undefined
        <p>No tasks available</p>
      )}
    </div>
  );
}

App.js(父组件)

import "./App.css";
import Textinserter from "./Components/Textinserter";
import DisplayTasks from "./Components/DisplayTasks";
import { useState } from "react";

export default function App() {
  const [tasks, setTasks] = useState([]); // Define tasks and setTasks in App component

  const handleTaskDeletion = (updatedTasks) => {
    setTasks(updatedTasks);
  };

  return (
    <div className="container mt-5">
      <Textinserter tasks={tasks} setTasks={setTasks} />
      <DisplayTasks tasks={tasks} onDelete={handleTaskDeletion} />
    </div>
  );
}

错误原因

问题出在DisplayTasks.js的删除按钮上:

<button className="btn btn-danger" onClick={deleteTask(task.id)}>
  Delete
</button>

这里直接调用deleteTask(task.id),会在组件渲染阶段就执行这个函数,进而触发onDelete调用父组件的setTasks更新状态。React禁止在渲染一个组件时更新另一个组件的状态,因此抛出警告。

修复方案

修改删除按钮的onClick事件,确保函数只在点击时执行,而不是渲染时。有两种常见方式:

方式1:使用箭头函数包裹

<button className="btn btn-danger" onClick={() => deleteTask(task.id)}>
  Delete
</button>

方式2:修改deleteTask返回一个函数

const deleteTask = (taskId) => () => {
  const updatedTasks = tasks.filter((task) => task.id !== taskId);
  onDelete(updatedTasks);
};

// 按钮部分保持不变
<button className="btn btn-danger" onClick={deleteTask(task.id)}>
  Delete
</button>

修改后的完整DisplayTasks.js代码

import React from "react";

// Component to display tasks
export default function DisplayTasks({ tasks, onDelete }) {
  const deleteTask = (taskId) => {
    // Filter out the task with the matching ID and update tasks array
    const updatedTasks = tasks.filter((task) => task.id !== taskId);
    onDelete(updatedTasks);
  };

  // Styling for the main container
  const myStyle = {
    backgroundColor: "#0D6EFD",
    padding: "15px",
    borderRadius: "10px",
  };

  return (
    <div
      // Conditional styling based on the tasks length
      style={
        tasks.length === 0 ? { ...myStyle, visibility: "hidden" } : myStyle
      }
    >
      {/* Heading for the tasks */}
      <h1 className="text-center text-light mb-4">Today's Tasks</h1>

      {tasks && tasks.length > 0 ? ( // Check if tasks exist and not empty
        <ul className="list-group" style={{ width: "100%" }}>
          {tasks.map((task) => (
            <div
              key={task.id}
              className="d-flex justify-content-between align-items-center"
            >
              {/* Container for each task */}
              <span
                className="d-inline-block w-100 overflow-hidden m-2"
                style={{ borderRadius: "10px" }} // Styling for each task container
              >
                {/* List item for the task */}
                <li className="list-group-item" aria-current="true">
                  {task.name}
                </li>
              </span>
              {/* 修改这里:用箭头函数包裹deleteTask调用 */}
              <button className="btn btn-danger" onClick={() => deleteTask(task.id)}>
                Delete
              </button>
            </div>
          ))}
        </ul>
      ) : (
        // Display if tasks array is empty or undefined
        <p>No tasks available</p>
      )}
    </div>
  );
}

验证

修改后,组件渲染时不会执行删除逻辑,只有点击"Delete"按钮时才会触发状态更新,警告会消失。

内容的提问来源于stack exchange,提问作者shaikh_sanan_007

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 09:52:07