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

Material UI Select组件值为列表项时无法显示选中选项

问题描述

我有一个MUI React Select组件,原本将更新后的event.value作为简单字符串使用时,组件可以正常工作,原代码如下:

import React, { useState, useEffect, Fragment } from 'react';
import { Box, Input, MenuItem, FormControl, Select, InputLabel, CircularProgress, Button } from '@mui/material';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import axios from "axios";

function ProductSelect() {
    const [loadingData, setLoadingData] = useState(true);
    const [productType, setProductType] = useState('');
    const [productTypes, setProductTypes] = useState([]);
    const [runmode, setRunmode] = useState('dev');

    async function getProducts() {
        await axios
        .get(`https://myendpoint.myregion.mycloud.com/${ runmode }/product_types`, {
            headers: {
                'Content-Type': 'application/json'
            }
        })
        .then((response) =>{
            var test_data = response.data.data;
            setProductTypes(
                test_data.map((x) => {
                    return {
                        product_name: `${x.product_name}`,
                        product_type_id: parseInt(`${x.product_type_id}`),
                    }
                })
            );
            setLoadingData(false);
        });
    }

    useEffect(() => {
        getProducts();
        if (loadingData) {
            getProducts();
        }
    }, []);

    const handleProductTypeChange = (event) => {
        setProductType(event.target.value);
    };

    const theme = createTheme({
        palette: {
          neutral: {
            main: '#24507C',
            contrastText: '#fff',
          },
        },
    });

    return (
        <div>
            <ThemeProvider theme={theme}>
             {loadingData ? (
                <Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', marginBottom: '185px' }}>
                    <CircularProgress/>
                    <span style={{ justifyContent: "center", position: "fixed", top: "30%" }}>Loading. Please wait...</span>
                </Box>  
              ) : (
                <>
                    <FormControl style={{width: '250px', marginTop: '0px', marginBottom: '30px'}}>
                        <InputLabel id="demo-simple-select-label">Product Type</InputLabel>
                        <Select
                            labelId="demo-simple-select-label"
                            id="demo-simple-select"
                            value={productType}
                            label="Product Type"
                            onChange={handleProductTypeChange}
                        > 
                        {productTypes.map((option) => (
                            <MenuItem key={option.product_type_id} value={option.product_name} >
                                {option.product_name}
                            </MenuItem>
                        ))}
                        </Select>
                    </FormControl>
                </>    
              )}
              <Button color="neutral" variant="contained" cursor="pointer">Schedule</Button>
            </ThemeProvider>
        </div>
    );
};
export default ProductSelect;  

但productTypes中的每个项包含product_type_id和product_name两个键值对,我希望将MenuItem的value改为数组,同时传递这两个值,修改后的MenuItem代码如下:

<MenuItem key={option.product_type_id} value={[option.product_name, option.product_type_id]} >

并在处理函数中取数组第一个元素更新productType:

const handleProductTypeChange = (event) => {
    setProductType(event.target.value[0]);
};

此时处理函数能获取到正确值,但选中的选项无法显示,请问我哪里出错了?


问题原因及解决方案

核心问题

MUI的Select组件通过**严格相等(===)**匹配Select的value属性和MenuItem的value,以此确定选中项并显示。你当前的Select绑定的productType是字符串类型,但MenuItem的value是数组类型,两者类型不匹配,严格相等比较失败,导致组件无法识别选中项,所以不会显示选中内容。

解决方案

统一Select和MenuItem的value类型即可,推荐用对象传递多值(比数组可读性更强):

  1. 修改MenuItem的value为对象:
<MenuItem key={option.product_type_id} value={{ name: option.product_name, id: option.product_type_id }} >
    {option.product_name}
</MenuItem>
  1. 调整productType的初始状态为对象,更新处理函数:
// 初始状态改为空对象
const [productType, setProductType] = useState({});

const handleProductTypeChange = (event) => {
    setProductType(event.target.value);
};
  1. 给Select添加renderValue属性,指定选中时显示的文本:
<Select
    labelId="demo-simple-select-label"
    id="demo-simple-select"
    value={productType}
    label="Product Type"
    onChange={handleProductTypeChange}
    // 自定义选中时显示的内容
    renderValue={(selected) => selected.name || ''}
>

如果坚持用数组,也需要统一类型:

  • 将productType初始状态改为空数组[]
  • 处理函数直接保存整个数组:setProductType(event.target.value);
  • 添加renderValue:renderValue={(selected) => selected[0] || ''}

完整修改后的代码示例

import React, { useState, useEffect, Fragment } from 'react';
import { Box, MenuItem, FormControl, Select, InputLabel, CircularProgress, Button } from '@mui/material';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import axios from "axios";

function ProductSelect() {
    const [loadingData, setLoadingData] = useState(true);
    // 初始状态改为空对象
    const [productType, setProductType] = useState({});
    const [productTypes, setProductTypes] = useState([]);
    const [runmode, setRunmode] = useState('dev');

    async function getProducts() {
        try {
            const response = await axios.get(`https://myendpoint.myregion.mycloud.com/${ runmode }/product_types`, {
                headers: {
                    'Content-Type': 'application/json'
                }
            });
            const test_data = response.data.data;
            setProductTypes(
                test_data.map((x) => ({
                    product_name: x.product_name,
                    product_type_id: parseInt(x.product_type_id, 10),
                }))
            );
            setLoadingData(false);
        } catch (error) {
            console.error('获取产品类型失败:', error);
            setLoadingData(false);
        }
    }

    useEffect(() => {
        getProducts();
        // 移除重复调用逻辑,避免重复请求
    }, []);

    const handleProductTypeChange = (event) => {
        setProductType(event.target.value);
    };

    const theme = createTheme({
        palette: {
          neutral: {
            main: '#24507C',
            contrastText: '#fff',
          },
        },
    });

    return (
        <div>
            <ThemeProvider theme={theme}>
             {loadingData ? (
                <Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', marginBottom: '185px' }}>
                    <CircularProgress/>
                    <span style={{ justifyContent: "center", position: "fixed", top: "30%" }}>Loading. Please wait...</span>
                </Box>  
              ) : (
                <>
                    <FormControl style={{width: '250px', marginTop: '0px', marginBottom: '30px'}}>
                        <InputLabel id="demo-simple-select-label">Product Type</InputLabel>
                        <Select
                            labelId="demo-simple-select-label"
                            id="demo-simple-select"
                            value={productType}
                            label="Product Type"
                            onChange={handleProductTypeChange}
                            renderValue={(selected) => selected.name || ''}
                        > 
                        {productTypes.map((option) => (
                            <MenuItem key={option.product_type_id} value={{ name: option.product_name, id: option.product_type_id }} >
                                {option.product_name}
                            </MenuItem>
                        ))}
                        </Select>
                    </FormControl>
                </>    
              )}
              <Button color="neutral" variant="contained" cursor="pointer">Schedule</Button>
            </ThemeProvider>
        </div>
    );
};
export default ProductSelect;  

额外优化提示

  • 移除了useEffect中重复调用getProducts的逻辑,避免重复发起请求
  • 给axios请求添加了try/catch,处理请求失败的情况,防止页面一直处于加载状态
  • 给parseInt添加了第二个参数10,确保十进制解析,避免意外问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 20:46:12