动态加载选项至Multiselect组件首次加载失效问题排查
问题:multiselect-react-dropdown动态加载选项失败
使用multiselect-react-dropdown实现多选框,选项通过API动态获取,但多选框在API请求完成前就已渲染,导致选项无法加载。尝试通过useEffect延迟组件渲染、添加businessUnits &&判断渲染时机均无效,控制台显示businessUnits数组先打印两次空值,之后才出现包含有效数据的数组。
解决方案
1. 修正初始状态与渲染判断
将businessUnits的初始状态设为null而非空数组,这样businessUnits && ...的条件判断会在API未返回数据时不渲染多选框组件,避免组件提前接收空数组完成渲染。
2. 修复多选框选中状态的更新逻辑
原组件中selectedValues仅初始化但未设置更新方法,导致选中状态无法同步,需添加对应的状态更新函数并绑定到多选框的onSelect和onRemove事件。
3. 匹配displayValue属性与选项结构
转换后的选项对象是{ label: item.name, value: item.code },因此displayValue需设为"label"而非原代码中的"name",确保下拉列表能正确显示选项文本。
4. 优化API请求写法
使用async/await替代链式then,让代码更简洁易读,同时统一错误处理逻辑。
修改后的代码
LotList主组件
import React, { useState, useEffect } from 'react'; import { Container, Row, Col, Form } from 'react-bootstrap'; import DateRange from '../DateRange'; import SiteComponentLoader from '../SiteComponentLoader'; import MultiselectBox from '../Utilities/MultiselectBox'; import { fetchDataAuthenticated } from '../Utilities/HttpUtils'; import useAlert from '../Alerts/useAlert'; function LotList({ status }) { status ??= ""; const defaultDateRange = { from: null, to: null }; const { setAlert } = useAlert(); // 初始状态设为null,确保条件判断生效 const [businessUnits, setBusinessUnits] = useState(null); const option = item => ({ label: item.name, value: item.code }); useEffect(() => { async function getBusinessUnits() { try { const response = await fetchDataAuthenticated("api/v1/businessunit"); if (!response.ok) throw new Error("Failed to get business units"); const data = await response.json(); setBusinessUnits(data.map(option)); } catch (error) { setAlert("danger", "Error", error.message); } } getBusinessUnits(); }, []); const [dateFilter, setDateFilter] = useState(defaultDateRange); const [includeGraded, setIncludeGraded] = useState(false); const handleIncludeGraded = (e) => { setIncludeGraded(e.target.checked); } return ( <Container fluid> <Row className="d-flex align-items-center mb-3"> <Col className="d-flex justify-content-start"> <DateRange dateFilter={dateFilter} setDateFilter={setDateFilter} /> </Col> <Col className="d-flex justify-content-middle"> {/* 数据返回后再渲染多选框 */} {businessUnits && <MultiselectBox businessUnits={businessUnits} />} </Col> <Col className="d-flex justify-content-end pt-2"> <Form.Check type="checkbox" onChange={handleIncludeGraded} className="me-2" style={{ marginTop: "-0.5rem" }} /> <Form.Label>Include graded items?</Form.Label> </Col> </Row> <Row> <SiteComponentLoader component="./Pages/LotListTable" site="SCP" tableFilters={{ status, dateFilter, includeGraded }} /> </Row> </Container> ); } export default LotList;
MultiselectBox组件
import React, { useState } from 'react'; import { Form, Row } from 'react-bootstrap'; import Multiselect from 'multiselect-react-dropdown'; function MultiselectBox({ businessUnits }) { // 添加状态更新函数,支持选中/移除选项 const [selectedValues, setSelectedValues] = useState([]); return ( <Form.Group as={Row} className="me-3" controlId="title"> <Form.Label>Business Units: </Form.Label> <Multiselect options={businessUnits} selectedValues={selectedValues} onSelect={setSelectedValues} onRemove={setSelectedValues} displayValue="label" // 匹配转换后的选项属性 loading={!businessUnits} // 根据数据状态控制loading显示 /> </Form.Group> ); } export default MultiselectBox;
内容的提问来源于stack exchange,提问作者shizz
相关产品推荐
相关产品推荐

