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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 21:52:51