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

MERN项目下拉加载MongoDB数据报错:TypeError: group.map is not a function

问题:React下拉菜单渲染分组数据时抛出TypeError: group.map is not a function错误

在React应用中尝试将MongoDB中的分组数据渲染为下拉菜单选项,用于添加库存项时指定对应分组。但切换下拉选项时,抛出错误:TypeError: group.map is not a function。以下是AddInventoryForm.jsx的代码,尝试修改useState钩子但未解决问题。

import { useState, useEffect } from "react"
import { useNavigate } from 'react-router-dom'

const InventoryForm = () => {
    const initialState = {
        _id: '0',
        group_name: 'select_group',
        notes: 'null'
      }
    const [title, setTitle] = useState('')
    const [description, setDescription] = useState('')
    const [group, setGroup] = useState([initialState])
    const [status, setStatus] = useState('')
    const [error, setError] = useState(null)
    const navigate = useNavigate()

    
    useEffect(() => {
        // Fetch groups for dropdown list
        const fetchGroups = async () => {
            try {
                const response = await fetch('/api/groups')

                if (!response.ok) {
                    throw new Error('Failed to fetch group')
                }
                
                const contentType = response.headers.get('content-type')
                if (!contentType || !contentType.includes('application/json')) {
                    throw new Error('Invalid response format - expected JSON')
                }
                
                const json = await response.json()
                console.log("Groups = ", json)
                setGroup(json)
            } catch (error) {
                console.error('Error fetching group:', error)
            }
        }
        fetchGroups()
    }, [])

    
    const handSubmit = async (e) => {
        e.preventDefault()

        const inventory = {title, description, group, status}

        // Manual check for if group dropdown has been changed
        if(group==='select_group') {
            return setError("Group is required")
        }

        const response = await fetch('/api/inventory', {
            method: 'POST',
            body: JSON.stringify(inventory),
            headers: {
                'Content-Type': 'application/json'
            }
        })
        console.log(response)
        const json = await response.json()

        

        if(!response.ok) {
            setError(json.error)
        }
        if(response.ok) {
            //setTitle("")
            //setDescription("")
            //setGroup("")
            //setStatus("")
            setError(null)
            console.log("New inventory item added", json)

            // Alert user
            alert("Item added")
            
            // Navigate back to inventory
            navigate("/inventory/")
        }


    }
    return (
        <form className="create-inventory-form" onSubmit={handSubmit}>
            {/*<h3>Add Inventory Item</h3>*/}

            <label>Title</label> <br/>
            <input
                type="text"
                onChange={(e) => setTitle(e.target.value)}
                value={title}
            /> <br/>
            <label>Description</label> <br/>
            <input
                type="text"
                onChange={(e) => setDescription(e.target.value)}
                value={description} 
            /> <br/>
            <label>Group</label> <br/>

            <select
            value={initialState}
            onChange={(e) => setGroup(e.target.value)}>
                <option value={initialState}>Select Group</option>
                <option value={group.group_name}>{group.group_name}</option>

                {group && group.map((groupItem) => (
                <option key={groupItem._id} value={groupItem._id}>{groupItem.group_name}</option>))}

            </select><br/>
            <label>Status</label> <br/>
            <input
                type="text"
                onChange={(e) => setStatus(e.target.value)}
                value={status} 
            /> <br/>

            <button>Submit</button>
            {error && <div className="error-msg">{error}</div>}
        </form>
    )
}

export default InventoryForm

问题分析与修复方案

核心问题

你把同一个group状态既用来存储所有分组的数组(渲染下拉选项),又用来存储用户选中的单个分组值,切换选项时数组被替换成字符串/单个值,后续调用group.map自然会报错。另外select组件的value和onChange逻辑也完全错误。

修复步骤

  1. 拆分状态:新增selectedGroup存储用户选中的分组ID,groups存储从后端拉取的分组数组
  2. 修正select绑定逻辑:value绑定selectedGroup,onChange时更新这个状态
  3. 移除无效代码:删掉<option value={group.group_name}>{group.group_name}</option>,这行完全无效
  4. 修正提交校验:检查selectedGroup是否为初始的'0',而不是group
  5. 调整初始状态:groups初始值设为空数组,避免渲染时的潜在问题

修改后的完整代码

import { useState, useEffect } from "react"
import { useNavigate } from 'react-router-dom'

const InventoryForm = () => {
    const initialGroup = {
        _id: '0',
        group_name: 'select_group',
        notes: 'null'
    }
    const [title, setTitle] = useState('')
    const [description, setDescription] = useState('')
    // 拆分状态:groups存分组列表,selectedGroup存选中的分组ID
    const [groups, setGroups] = useState([])
    const [selectedGroup, setSelectedGroup] = useState(initialGroup._id)
    const [status, setStatus] = useState('')
    const [error, setError] = useState(null)
    const navigate = useNavigate()

    useEffect(() => {
        const fetchGroups = async () => {
            try {
                const response = await fetch('/api/groups')
                if (!response.ok) {
                    throw new Error('Failed to fetch group')
                }
                const contentType = response.headers.get('content-type')
                if (!contentType || !contentType.includes('application/json')) {
                    throw new Error('Invalid response format - expected JSON')
                }
                const json = await response.json()
                console.log("Groups = ", json)
                setGroups(json)
            } catch (error) {
                console.error('Error fetching group:', error)
            }
        }
        fetchGroups()
    }, [])

    const handSubmit = async (e) => {
        e.preventDefault()

        // 提交时使用选中的分组ID,可根据后端需求调整为分组对象
        const inventory = {title, description, group: selectedGroup, status}

        // 校验是否选择了有效分组
        if(selectedGroup === initialGroup._id) {
            return setError("Group is required")
        }

        try {
            const response = await fetch('/api/inventory', {
                method: 'POST',
                body: JSON.stringify(inventory),
                headers: {
                    'Content-Type': 'application/json'
                }
            })
            const json = await response.json()

            if(!response.ok) {
                setError(json.error)
            } else {
                setError(null)
                console.log("New inventory item added", json)
                alert("Item added")
                navigate("/inventory/")
            }
        } catch (submitError) {
            console.error('Error submitting inventory:', submitError)
            setError('Failed to add inventory item')
        }
    }

    return (
        <form className="create-inventory-form" onSubmit={handSubmit}>
            <label>Title</label> <br/>
            <input
                type="text"
                onChange={(e) => setTitle(e.target.value)}
                value={title}
                required
            /> <br/>
            <label>Description</label> <br/>
            <input
                type="text"
                onChange={(e) => setDescription(e.target.value)}
                value={description} 
                required
            /> <br/>
            <label>Group</label> <br/>

            <select
                value={selectedGroup}
                onChange={(e) => setSelectedGroup(e.target.value)}
                required
            >
                <option value={initialGroup._id}>{initialGroup.group_name}</option>
                {/* 确保groups是数组再渲染选项 */}
                {Array.isArray(groups) && groups.map((groupItem) => (
                    <option key={groupItem._id} value={groupItem._id}>{groupItem.group_name}</option>
                ))}
            </select><br/>
            <label>Status</label> <br/>
            <input
                type="text"
                onChange={(e) => setStatus(e.target.value)}
                value={status} 
                required
            /> <br/>

            <button>Submit</button>
            {error && <div className="error-msg">{error}</div>}
        </form>
    )
}

export default InventoryForm

额外优化点

  • 给表单控件加上required属性,利用HTML原生校验
  • 给提交逻辑添加try-catch,处理网络请求异常
  • 渲染选项时增加Array.isArray(groups)判断,进一步避免map报错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 01:32:04