React表单选择Office后设备下拉无选项问题求助
问题:React表单Office与Equipment Name联动失效
需求逻辑:
- 选择「Building Management Office」时,Equipment Name下拉框显示Spalding Basketball、Mikasa Volleyball;
- 选择「Information Technology and Resource Office」时,显示Nikon D300、Profoto B10 Plus Strobe Lights;
- 选择「Engineering and Science Laboratory Office」时,显示Pyrex Beaker、Pyrex Graduated Cycliner。
实际问题:选择对应Office后,设备下拉框无选项显示,尝试通过selectedItems变量匹配对应设备列表但未生效,相关代码如下:
import React, { useEffect } from "react"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import { DatePicker } from "@mui/x-date-pickers/DatePicker"; import { useForm, Controller } from "react-hook-form"; import Typography from "@mui/material/Typography"; import TextField from "@mui/material/TextField"; import Select from "react-select"; import Button from "@mui/material/Button"; import InnerContainer from "./InnerContainer"; const sample_bmo_item = [ { label: "Spalding Basketball", value: "101", }, { label: "Mikasa Volleyball", value: "102", }, ]; const sample_itro_item = [ { label: "Nikon D300", value: "201", }, { label: "Profoto B10 Plus Strobe Lights", value: "202", }, ]; const sample_eslo_item = [ { label: "Pyrex Beaker", value: "301", }, { label: "Pyrex Graduated Cycliner", value: "302", }, ]; const offices = [ { label: "Building Management Office", value: "Building Management Office" }, { label: "Information Technology and Resource Office", value: "Information Technology and Resource Office", }, { label: "Engineering and Science Laboratory Office", value: "Engineering and Science Laboratory Office", }, ]; const purposes = [ { label: "Academic Purposes - Assignment & Activities", value: "Academic Purposes - Assignment & Activities", }, { label: "Organization Purposes", value: "Organization Purposes" }, { label: "Academic Purposes - Midterms & Finals", value: "Academic Purposes - Midterms & Finals", }, { label: "Special Events", value: "Special Events" }, { label: "Others", value: "Others" }, ]; const endorser = [ { label: "Ms. -", value: "Ms. -", }, { label: "Sir. -", value: "Sir. -", }, { label: "Ms. -", value: "Ms. -", }, { label: "Ms. -", value: "Ms. -", }, { label: "Ms. -", value: "Ms. -", }, ]; const BorrowForm = () => { const { control, handleSubmit, setValue, watch } = useForm(); const selectedPurpose = watch("purposes"); const selectedOffice = watch("offices"); const selectedItems = selectedOffice === "Building Management Office" ? sample_bmo_item : selectedOffice === "Information Technology and Resource Office" ? sample_itro_item : selectedOffice === "Engineering and Science Laboratory Office" ? sample_eslo_item : []; const onSubmit = (data) => { console.log("submit hit with data:", data); }; useEffect(() => { console.log("selected purpose changed to:", selectedPurpose); }, [selectedPurpose]); return ( <InnerContainer> <LocalizationProvider dateAdapter={AdapterDayjs}> <form onSubmit={handleSubmit(onSubmit)}> <div className="borrowing-transaction"> <Typography>Borrowing Information</Typography> <div className="endorser"> <Typography>Endorsed By</Typography> <Controller name="endorser" control={control} render={({ field }) => <Select {...field} options={endorser} />} /> </div> <div className="office"> <Typography>Office</Typography> <Controller name="offices" control={control} defaultValue="" render={({ field }) => <Select {...field} options={offices} />} /> </div> <div className="purposes"> <Typography>Purpose</Typography> <Controller name="purposes" control={control} render={({ field }) => ( <Select options={purposes} {...field} value={purposes.find((c) => c.value === field.value?.value)} /> )} /> </div> <div className="specific-purpose"> <Typography>Specific Purpose</Typography> <TextField label="Enter Specific Purpose" variant="filled" fullWidth style={{ backgroundColor: selectedPurpose?.value === "Others" ? "white" : "yellow", }} disabled={selectedPurpose?.value === "Others" ? false : true} onChange={(e) => setValue("specificPurposeInputText", e.target.value) } /> </div> <div className="date-pickers"> <Typography>Starting Date</Typography> <Controller control={control} name="start-date" render={({ field }) => ( <DatePicker placeholderText="Select date" onChange={(date) => field.onChange(date)} selected={field.value} /> )} /> <Typography>Returning Date</Typography> <Controller control={control} name="return-date" render={({ field }) => ( <DatePicker placeholderText="Select date" onChange={(date) => field.onChange(date)} selected={field.value} /> )} /> </div> </div> <div className="items"> <Typography>Item</Typography> <div className="oneby"> <div className="equipment-name"> <Typography>Equipment Name</Typography> <Controller control={control} name="equipmentName" render={({ field }) => ( <Select {...field} options={selectedItems} /> )} /> </div> <div className="start-date-item"> <Typography>Starting Date</Typography> <Controller control={control} name="return-date-item" render={({ field }) => ( <DatePicker placeholderText="Select date" onChange={(date) => field.onChange(date)} selected={field.value} /> )} /> </div> <div className="return-date-item"> <Typography>Returning Date</Typography> <Controller control={control} name="return-date" render={({ field }) => ( <DatePicker placeholderText="Select date" onChange={(date) => field.onChange(date)} selected={field.value} /> )} /> </div> <div className="quantity"></div> <Typography>Quantity</Typography> <TextField id="outlined-number" label="Number" type="number" InputLabelProps={{ shrink: true, }} /> </div> </div> <Button type="submit" variant="contained" color="primary"> Submit </Button> </form> </LocalizationProvider> </InnerContainer> ); }; export default BorrowForm;
问题排查与解决方案
核心问题
watch("offices")获取到的是整个选项对象(比如{ label: "Building Management Office", value: "Building Management Office" }),而非字符串类型的value值。原代码中直接用selectedOffice === "Building Management Office"进行判断,条件永远不成立,导致selectedItems始终为空数组[]。
修复步骤
- 修正selectedItems的判断逻辑:
将判断条件改为使用selectedOffice?.value匹配字符串:
const selectedItems = selectedOffice?.value === "Building Management Office" ? sample_bmo_item : selectedOffice?.value === "Information Technology and Resource Office" ? sample_itro_item : selectedOffice?.value === "Engineering and Science Laboratory Office" ? sample_eslo_item : [];
- 可选:重置Equipment Name选中值
切换Office时,清空之前选中的设备值,避免残留无效选项,添加useEffect:
useEffect(() => { setValue("equipmentName", null); }, [selectedOffice, setValue]);
- 可选:完善Office的默认值
原代码中Office的Controller设置了defaultValue="",但react-select的默认值应为对应选项对象或null,修改为:
<Controller name="offices" control={control} defaultValue={null} // 改为null,匹配react-select的默认值规范 render={({ field }) => <Select {...field} options={offices} />} />
修复后效果
选择对应Office后,Equipment Name下拉框会自动加载对应设备列表,切换Office时设备选择框会清空之前的选中值,符合预期联动逻辑。
内容的提问来源于stack exchange,提问作者notyouraveragetoru
相关产品推荐
相关产品推荐

