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

React待办列表开发问题:点击两次才打印、map不渲染及渲染后清空state

React待办列表问题解决方案

问题1:点击addTask按钮需要两次才能打印最新todoList

原因

React的状态更新是异步批量执行的,调用setTodoList后,当前作用域下的todoList还是本次渲染周期的旧值,所以第一次点击打印的是更新前的数组,第二次点击才能拿到上一次更新的结果。

解决方法

如果只是要查看更新后的值,直接打印你传入setTodoList的新数组即可,如果需要在状态更新后执行逻辑,可以用useEffect监听todoList变化:

const AddTask = (e) => {
  const newTodoList = [...todoList, task]
  setTodoList(newTodoList);
  // 直接打印新数组就能拿到最新值
  console.log(newTodoList);
  // 清空输入框 对应问题3的需求
  setTask("")
};

// 如果需要监听状态变化执行其他逻辑
useEffect(() => {
  console.log("todoList更新了:", todoList)
}, [todoList])

问题2:todoList有值但map不渲染内容

错误点

  1. 第一个map的回调函数用了大括号包裹但没有写return,没有返回要渲染的DOM元素,React自然不会渲染内容
  2. 条件判断todoList !== ""逻辑错误,todoList是数组类型,空数组和空字符串比较永远返回true,判断是否有值应该用todoList.length > 0
  3. 遍历生成的元素没有加唯一key属性,会触发React警告

修正后的渲染代码

{todoList.length > 0 ? (
  todoList.map((insertTask, index) => (
    // 用index做key是临时方案,实际场景建议用任务唯一id
    <div key={index}>
      <p>{insertTask}</p>
      <button onClick={switchEnCours}>{encours}</button>
    </div>
  ))
) : <div></div>}

提示:回调函数不用大括号改用小括号可以实现隐式返回,不需要额外写return

问题3:渲染后清空对应state

  • 清空输入框内容:调用setTask(""),建议直接放在AddTask逻辑最后,添加完任务自动清空
  • 清空整个待办列表:调用setTodoList([])即可
  • 清空任意状态值只需要调用对应state的set方法传入初始值即可

完整修正后代码

import { useState, useEffect } from 'react'

function Task() {
  const [task, setTask] = useState("");
  const [encours, setEncours] = useState("en cours");
  const [todoList, setTodoList] = useState([]);

  const switchEnCours = () => {
    setEncours("terminé");
  };

  const deleteTask = () => {
    setEncours("supprimée");
  };

  const handleInput = (e) => {
    // 这里不需要preventDefault,onChange事件不需要阻止默认行为
    setTask(e.target.value);
  };
  const AddTask = (e) => {
    const newTodoList = [...todoList, task]
    setTodoList(newTodoList);
    // 清空输入框
    setTask("")
    console.log(newTodoList);
  };

  return (
    <div>
      <input value={task} onChange={handleInput}></input>
      <button onClick={AddTask}>Valider</button>
      <div className="DivColonne">
        <div className="Colonne">
          <h1>Tâche à faire</h1>
          {todoList.length > 0 ? (
            todoList.map((insertTask, index) => (
              <div key={index}>
                <p>{insertTask}</p>
                <button onClick={switchEnCours}>{encours}</button>
              </div>
            ))
          ) : (
            <div></div>
          )}
        </div>
        <div className="Colonne">
          <h1>Tâche en cours</h1>
          {encours === "terminé" ? (
            <div>
              {todoList.map((insert, index) => {
                return (
                  <div key={index}>
                    <p>{insert}</p>
                    <button onClick={deleteTask}>{encours}</button>
                  </div>
                );
              })}
            </div>
          ) : (
            <div></div>
          )}
        </div>
        <div>
          <h1>Tâches terminées</h1>
          {encours === "supprimée" ? (
            <div>
              <p>{todoList}</p>
            </div>
          ) : (
            <div></div>
          )}
        </div>
      </div>
    </div>
  );
}

export default Task;

额外提示:你当前的encours状态是全局共享的,点击一个任务的按钮会修改所有任务的状态,实际要实现单个任务状态变更的话,需要把每个任务的状态存在todoList的每一项里,而不是用全局的encours状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 09:54:04