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 insideDisplayTasks, 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
相关产品推荐
相关产品推荐

