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

删除任意Route条目时持续触发TypeError: Cannot read properties of null (reading 'items')

问题:删除待办条目时出现 TypeError: Cannot read properties of null (reading 'items')

在基于Express、Mongoose开发的待办清单应用中,删除任意路由下的条目时,反复触发错误:TypeError: Cannot read properties of null (reading 'items')。

错误原因

  1. EJS模板输入值未加引号:模板中listName隐藏输入框的value属性未用引号包裹,当列表名称包含空格或特殊字符时,后端接收到的listName值会被截断或解析错误,导致List.findOne无法找到对应文档,返回null,后续访问foundList.items自然报错。
  2. 异步代码风格混乱:删除路由混合使用回调和Promise,未妥善处理异步操作的完成时机,增加了空值出现的概率。
  3. 废弃API使用:Mongoose的findByIdAndRemove已被废弃,存在潜在兼容性问题。

修复方案

1. 修复EJS模板的隐藏输入框

给listName的value属性添加引号,确保值被正确传递:

<input type="hidden" name="listName" value="<%= listTitle %>">

2. 统一使用async/await重构删除路由

彻底替换回调,用async/await处理异步操作,明确空值判断逻辑:

app.post("/delete", async function(req, res) {
  const checkedItemId = req.body.checkbox;
  const listName = req.body.listName;

  console.log("checkboxID: " + checkedItemId);

  if (listName === "Today") {
    try {
      // 使用废弃API的替代方法findByIdAndDelete
      await Item.findByIdAndDelete(checkedItemId);
      console.log("Successfully deleted item.");
      res.redirect("/");
    } catch (err) {
      console.log(err);
      res.redirect("/");
    }
  } else {
    try {
      const foundList = await List.findOne({ name: listName });
      if (foundList && foundList.items) {
        foundList.items.pull({ _id: checkedItemId });
        await foundList.save();
        res.redirect("/" + listName);
      } else {
        console.log("List or items not found.");
        res.redirect("/" + listName);
      }
    } catch (err) {
      console.log(err);
      res.redirect("/" + listName);
    }
  }
});

3. 优化自定义列表相关的异步逻辑

自定义列表创建时等待保存完成

将app.get("/:customListName")改为async函数,等待列表保存后再重定向:

app.get("/:customListName", async function(req, res) {
  const customListName = req.params.customListName;
  const requestedUrl = req.originalUrl;
  
  if (requestedUrl === "/favicon.ico") {
    res.status(204).end();
    return;
  }

  const foundList = await List.findOne({name: customListName});
  if(!foundList){
    const list = new List({
      name: customListName,
      items: []
    });
    await list.save();
    res.redirect("/" + customListName);
  } else {
    res.render("list", {
      listTitle: foundList.name,
      newListItems: foundList.items,
    });
  }
});

自定义列表添加条目时等待保存完成

重构app.post("/:customListName?"),确保条目保存后再重定向:

app.post("/:customListName?", async function(req, res) {
  const customListName = req.params.customListName;
  const newItem = req.body.newItem;

  const item = new Item({
    name: newItem
  });

  if (customListName) {
    try {
      const foundList = await List.findOne({ name: customListName });
      foundList.items.push(item);
      await foundList.save();
      res.redirect("/" + customListName);
    } catch (error) {
      console.log(error);
      res.redirect("/" + customListName);
    }
  } else {
    await item.save();
    res.redirect("/");
  }
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 22:35:05