使用useRecoilState添加Todo项时出现undefined问题求助
Recoil添加Todo项出现undefined的问题修复
问题根源
你遇到的核心问题是:在调用setToDoList后立刻清空了ref的value,而Recoil的状态更新回调会在当前同步代码执行完毕后才触发。由于ref的current是可变引用,当回调执行时,ref的值已经被清空,导致构造待办项时读取到的是空字符串,最终生成的项属性变成无效值(比如id为NaN、date为Invalid Date),看起来像是undefined。
修复方案
在调用setToDoList前,先把ref的当前值保存到本地变量中,用这些变量来构造待办项,之后再清空ref。这样即使后续修改ref,回调里用的也是保存好的有效值。
修改后的ToDoCreator.js代码:
////ToDoCreator.js//// import { useRef } from "react"; import { useSetRecoilState } from "recoil"; import { toDoListState } from "../recoil_state.js" export default function ToDoCreator(){ const idRef = useRef(null); const todoRef = useRef(null); const dateRef = useRef(null); const setToDoList = useSetRecoilState(toDoListState); const create =() => { // 先保存ref的当前值到变量 const idValue = idRef.current.value; const todoValue = todoRef.current.value; const dateValue = dateRef.current.value; if(idValue === "" || todoValue === "" || dateValue === ""){ alert("All fields required!"); } else if(isNaN(idValue)){ alert("ID must be a number!"); } else if(!Date.parse(dateValue)){ alert("Invalid Date!"); // 修正原拼写错误:Invalide → Invalid } else{ setToDoList((current) => [ ...current, { id: Number(idValue), text: todoValue, date: new Date(dateValue), } ]); // 清空输入框 idRef.current.value = ""; todoRef.current.value = ""; dateRef.current.value = ""; } } return( <div> <input type="text" placeholder="ID" ref={idRef} /> <input type="text" placeholder="To-Do" ref={todoRef} /> <input type="text" placeholder="Date" ref={dateRef} /> <button onClick={create}>Save</button> </div> ) }
额外优化建议
你的filteredToDoListState中,直接用Date对象和字符串比较会导致结果不准确(因为Date对象转字符串后的格式与输入的日期字符串格式不一致)。建议把过滤条件中的字符串也转为Date对象,通过时间戳比较:
修改后的recoil_state.js中selector部分:
export const filteredToDoListState = selector({ key: "filteredToDoListState", get: ({get}) => { const filter = get(filterState); const list = get(toDoListState); // 将过滤日期转为Date对象(空字符串则为null) const startDate = filter[0] ? new Date(filter[0]) : null; const endDate = filter[1] ? new Date(filter[1]) : null; if (!startDate && !endDate){ return list; } else if (!startDate){ // 比较时间戳确保准确性 return list.filter(item => item.date.getTime() <= endDate.getTime()); } else if (!endDate){ return list.filter(item => item.date.getTime() >= startDate.getTime()); } else { // 注意:原逻辑是||,如果需要筛选[startDate, endDate]区间内的项,应改为&& return list.filter(item => item.date.getTime() >= startDate.getTime() || item.date.getTime() <= endDate.getTime() ); } } })
注:如果你的需求是筛选起始日期到结束日期之间的待办项,需要把最后一个条件的
||改为&&,否则当前逻辑会包含所有项(当startDate在endDate之前时)。
内容的提问来源于stack exchange,提问作者MyName
相关产品推荐
相关产品推荐

