React v18实现依赖级联select字段选项自动选中的方法
React 18 关联选择框实现方案
问题根因
你遇到的两个问题本质是同一个原因:没有将三个select做成受控组件,既没有存储各字段的当前选中值,也没有将select的选中状态和组件状态绑定:
- 没有全局存储选中值,选产品的时候自然拿不到当前已选的分类值
- 没有给select绑定value属性,哪怕拿到了需要选中的值,组件也不会自动切换选中项
具体修改步骤
- 新增3个状态,分别存储三个选择框的当前选中值
- 给每个
<select>标签绑定value属性,关联对应状态,实现状态和选中项的双向绑定——只要更新状态值,select会自动选中对应value的option,不需要手动操作DOM - 调整各个选择事件的逻辑:
- 选中分类时:更新分类选中状态,拉取对应分类的产品列表,同时清空已选的产品和ID,避免出现跨分类的无效值
- 选中ID时:拉取对应详情,拿到分类和产品信息后更新三个选中状态,同时同步刷新对应分类下的产品列表
- 选中产品时:直接从状态里读取当前已选的分类值,和产品值一起传给接口查对应ID,拿到ID后更新ID选中状态
- (可选)之前react-select不生效是因为它要求选项格式为
{value: 选项值, label: 显示文本},把接口返回的原始列表按这个格式转一下就能正常用。
修改后完整代码
-------------------------------- dselect.js -------------------------------- import {Row, Col, Container} from "react-bootstrap" import React, { useState, useEffect } from 'react'; const baseurl = "http://localhost:5000/api"; const Dselect=()=>{ // 列表类状态 const [catList, setCatList] = useState([]); const [pdtList, setPdtlist] = useState([]); // 选中值状态,核心用于受控绑定和跨字段取值 const [selectedId, setSelectedId] = useState(""); const [selectedCategory, setSelectedCategory] = useState(""); const [selectedProduct, setSelectedProduct] = useState(""); // 初始化拉取分类和全量产品列表 useEffect(()=>{ const fetchCat = async() => { const res = await fetch(`${baseurl}/cat`); const cList = await res.json(); setCatList(cList) } const fetchAllPdt = async() => { const res = await fetch(`${baseurl}/pdtlist`); const pList = await res.json(); setPdtlist(pList) } fetchCat(); fetchAllPdt(); },[]) // 选中ID时联动分类和产品 const getPdtDetails = async(e) => { const pdtID = e.target.value; setSelectedId(pdtID); // 选空值时重置其他选项 if(!pdtID) { setSelectedCategory(""); setSelectedProduct(""); const res = await fetch(`${baseurl}/pdtlist`); const pList = await res.json(); setPdtlist(pList); return; } const res = await fetch(`${baseurl}/details`,{ method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({data:pdtID}), }); const detList = await res.json(); // 更新分类和产品的选中状态,select会自动选中对应项 setSelectedCategory(detList.category); setSelectedProduct(detList.pdt_id); // 同步拉取对应分类下的产品列表 const pdtRes = await fetch(`${baseurl}/pdtList`,{ method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({data:detList.category}), }); const catPdtList = await pdtRes.json(); setPdtlist(catPdtList); } // 选中分类时筛选对应产品 const updateList = async(e) =>{ const catVal = e.target.value; setSelectedCategory(catVal); // 切换分类时清空已选的产品和ID,避免无效值 setSelectedProduct(""); setSelectedId(""); if(!catVal) { // 选空分类时恢复全量产品列表 const res = await fetch(`${baseurl}/pdtlist`); const pList = await res.json(); setPdtlist(pList); return; } const res = await fetch(`${baseurl}/pdtList`,{ method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({data:catVal}), }); const catPdtList = await res.json(); setPdtlist(catPdtList) } // 选中产品时联动ID const getPdtcode = async(e) =>{ const pdtVal = e.target.value; setSelectedProduct(pdtVal); if(!pdtVal) { setSelectedId(""); return; } // 直接从状态取当前选中的分类值,不需要从事件对象获取 const currentCat = selectedCategory; const res = await fetch(`${baseurl}/pdtCode`,{ method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ pdtId: pdtVal, category: currentCat }), }); const code = await res.json(); // 更新ID选中状态,自动选中对应项 setSelectedId(code.pdt_id); } return( <div> <Container className="m-5"> <Row> <Col lg={4} md={4} xs={6}> <label>ID</label> {/* 绑定value到对应状态,实现受控 */} <select name="product_id" value={selectedId} onChange={getPdtDetails} > <option value="">-</option> {pdtList.map((item) =>( <option key={item.pdt_id} value={item.pdt_id}> {item.pdt_id} </option> ))} </select> </Col> <Col lg={4} md={4} xs={6}> <label>Category</label> <select name="category" value={selectedCategory} onChange={updateList} > <option value="">-</option> {catList.map((item) =>( <option key={item.cat_id} value={item.category}>{item.category}</option> ))} </select> </Col> <Col lg={4} md={4} xs={6}> <label>Product </label> <select name="product" value={selectedProduct} onChange={getPdtcode} > <option value="">-</option> {pdtList.map((item) =>( <option key={item.pdt_id} value={item.pdt_id}> {item.pdt_name} </option> ))} </select> </Col> </Row> </Container> </div> ) } export default Dselect
补充说明
如果后续要换回react-select,只需要把传入的options做格式转换即可,示例:
import Select from "react-select"; // 组件内使用示例 <Select options={pdtList.map(item => ({ value: item.pdt_id, label: item.pdt_name }))} value={selectedProduct ? { value: selectedProduct, label: pdtList.find(i => i.pdt_id === selectedProduct)?.pdt_name } : null} onChange={(opt) => { // 选中逻辑和原生select一致,取opt.value做后续处理即可 }} placeholder="Select product" />
内容的提问来源于stack exchange,提问作者Maya
相关产品推荐
相关产品推荐

