React关联MongoDB双Schema填充下拉框报错的解决方法
问题解决:React下拉框关联MongoDB双Schema时的报错处理
问题背景
我在MongoDB中有两个Schema:
- Assign Schema:包含
user_story_id和user_id字段 - User_story Schema:包含用户故事描述字段
需求是在React表单的下拉框中展示已分配的用户故事,需要关联两个Schema获取对应的ID与描述。以下是我的React实现代码,但运行时报错:
import React, { useState, useEffect } from 'react'; import 'bootstrap/dist/css/bootstrap.css'; import axios from 'axios'; export default function Task({}) { const [taskValues, setTaskValues] = useState({ task: '', userStory: 'userStory1', // Default value createdBy: 'user1', // Default value status: 'Pending', // Default value }); const [allTask, setAllTask] = useState([{}]); const [assigned, setAllAssign] = useState([{}]); const [allStories, setAllStories] = useState([{}]); const assignedUserStories = assigned.map((assigns) => { return assigns.user_story_id; }) const handleChange = (event) => { setTaskValues({ ...taskValues, [event.target.name]: event.target.value }); }; const loggedInUser = localStorage.getItem('loggedInUser') const handleCreateTask = (e) => { e.preventDefault(); const taskDetails = { task: taskValues.task, //captured from input task user_story_id: taskValues.userStory, //captured from dropdown status: taskValues.status, //captured from status dropdown created_by: loggedInUser } // Post taskValues data to your server endpoint axios.post('http://localhost:9000/createTask', taskValues) .then((res) => { if (res.data) { alert('Task creation Successful'); } }) .catch((err) => { alert('Error in creating the task'); }); }; useEffect(() => { axios.get('http://localhost:9000/getTaskList') .then(function (response) { const Taskdata = response.data; setAllTask(Taskdata); }); axios.get('http://localhost:9000/getUserstory') .then(function (response) { const Allstories = response.data; setAllStories(Allstories); }); }, []); const handleSubmit = (event) => { event.preventDefault(); }; return ( <div className="container mt-5"> <div className="row justify-content-center"> <div className="col-md-6 col-lg-4"> <div className="card"> <div className="card-body"> <h2 className="card-title">Create a New Task</h2> <form onSubmit={handleSubmit}> <div className="form-group"> <label>Task:</label> <textarea className="form-control" name="task" value={taskValues.task} onChange={handleChange} /> </div> <div className="form-group"> <label>User Story:</label> <select className="form-control" name="userStory" value={taskValues.userStory} onChange={handleChange} > {assignedUserStories.map((stories) => <option key={stories._id} value={stories._id}>{stories.user_story}</option> )} </select> </div> <div className="form-group"> <label>Created by:</label> <select className="form-control" name="createdBy" value={taskValues.createdBy} onChange={handleChange} > <option value="user1">User 1</option> <option value="user2">User 2</option> <option value="user3">User 3</option> </select> </div> <div className="form-group"> <label>Status:</label> <select className="form-control" name="status" value={taskValues.status} onChange={handleChange} > <option value="New">New</option> <option value="In Progress">In Progress</option> <option value="Awaiting Confirmation">Awaiting Confirmation</option> <option value="Completed">Completed</option> </select> </div> <button onClick={() => handleCreateTask()} className="btn btn-primary btn-block" > Assign </button> </form> </div> </div> </div> </div> </div> ); }
报错原因分析
- 未获取Assign数据:代码中仅请求了任务列表和用户故事列表,但没有调用接口获取Assign集合的数据,导致
assigned状态始终是初始的[{}],map后得到的assignedUserStories包含undefined,渲染时访问stories._id会报错。 - 初始状态不合理:用
[{}]作为数组初始值,第一次渲染时会处理空对象,引发属性读取错误。 - 数据关联逻辑错误:直接将
user_story_id当作完整的用户故事对象使用,无法获取到描述字段。
解决步骤
1. 补充Assign数据接口请求
在useEffect中添加获取Assign列表的请求,拿到已分配的用户故事ID:
useEffect(() => { axios.get('http://localhost:9000/getTaskList') .then(res => setAllTask(res.data)); axios.get('http://localhost:9000/getUserstory') .then(res => setAllStories(res.data)); // 新增:获取Assign集合数据 axios.get('http://localhost:9000/getAssignList') .then(res => setAllAssign(res.data)); }, []);
2. 修正初始状态
将数组初始值改为空数组,避免空对象干扰:
const [assigned, setAllAssign] = useState([]); const [allStories, setAllStories] = useState([]);
3. 正确关联双Schema数据
通过Assign中的user_story_id,从User_story集合中筛选出已分配的故事:
// 提取去重的已分配故事ID const assignedStoryIds = [...new Set(assigned.map(item => item.user_story_id))]; // 筛选出对应的用户故事 const assignedUserStories = allStories.filter(story => assignedStoryIds.includes(story._id));
4. 修正下拉框渲染逻辑
确保只在有数据时渲染选项,避免空数组报错:
<div className="form-group"> <label>User Story:</label> <select className="form-control" name="userStory" value={taskValues.userStory} onChange={handleChange} > {assignedUserStories.length > 0 ? ( assignedUserStories.map((story) => ( <option key={story._id} value={story._id}>{story.user_story}</option> )) ) : ( <option value="">暂无已分配的用户故事</option> )} </select> </div>
5. 其他优化点
- 状态命名优化:建议将
assigned改为assigns,setAllAssign改为setAssigns,避免命名混淆。 - 表单提交修正:
handleCreateTask中应提交构造好的taskDetails而非taskValues:axios.post('http://localhost:9000/createTask', taskDetails) - 默认值修正:将
taskValues.userStory的默认值改为空字符串,避免下拉框出现不存在的选项。
内容的提问来源于stack exchange,提问作者Encipher
相关产品推荐
相关产品推荐

