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不渲染内容
错误点
- 第一个map的回调函数用了大括号包裹但没有写
return,没有返回要渲染的DOM元素,React自然不会渲染内容 - 条件判断
todoList !== ""逻辑错误,todoList是数组类型,空数组和空字符串比较永远返回true,判断是否有值应该用todoList.length > 0 - 遍历生成的元素没有加唯一
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
相关产品推荐
相关产品推荐

