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

React实现两级分类联动下拉:选中一级分类后二级下拉加载对应子分类

两级分类联动下拉功能实现方案

原有代码核心问题

  • 状态设计混淆:将「子分类选项列表」和「表单选中值」两个完全独立的逻辑存到同一个sousCategories状态中,初始值设为对象也和后续接口返回的数组类型不匹配
  • 状态修改违规:直接对sousCategories[name]赋值不符合React状态不可变的更新原则
  • 渲染逻辑错误:子分类遍历的map方法没有返回值,且直接输出souscat对象会导致显示异常
  • 无效冗余代码:fetch请求配置中存在多余的data字段

修正后完整代码

import React,{useState,useEffect} from 'react';
import CategorieServices from '../../services/CategorieServices';

function DependentListBetweenCatAndSousCat(props) {
    // 父分类列表
    const [categories, setCategories] = useState([]);
    // 选中的父分类ID
    const [selectedCateId, setSelectedCateId] = useState('');
    // 子分类列表
    const [sousCategories, setSousCategories] = useState([]);
    // 选中的子分类ID
    const [selectedSousCateId, setSelectedSousCateId] = useState('');

    // 页面加载时拉取所有父分类
    useEffect(()=>{
        loadcategories();
    },[]);

    const loadcategories = async()=>{
        const results = await CategorieServices.categoriesAll("categories/all/");
        setCategories(results.data);
        // 如果有默认选中的父分类,初始化时直接拉取对应子分类
        if(props.courseId) {
            setSelectedCateId(props.courseId)
            loadSousCategories(props.courseId)
        }
    };

    // 拉取对应父分类的子分类列表
    const loadSousCategories = async (cateId) => {
        // 切换父分类时先清空原有子分类和选中值
        setSousCategories([])
        setSelectedSousCateId('')
        try {
            const response = await fetch("http://localhost:8000/api/sousCategorie/category/",{
                method:"POST",
                headers:{
                    "Content-Type":"application/json",
                },
                body: JSON.stringify({ id: cateId }),
            })
            const myJson = await response.json()
            setSousCategories(myJson)
        } catch (err) {
            console.error('子分类拉取失败', err)
        }
    }

    // 父分类切换触发
    const selectCategory=(e)=>{
        const cateId = e.target.value
        setSelectedCateId(cateId)
        loadSousCategories(cateId)
    };
    
    return (
        <div className="selectoption d-flex">
            {/* 父分类选择框 */}
            <select 
                name="categorieName" 
                value={selectedCateId}
                onChange={selectCategory}
            >
                {categories.map((cate)=>
                <option value={cate.id} key={cate.id}>{cate.name}</option>
                )}
            </select>
            {/* 子分类选择框 */}
            <select 
                name="sousCategorieName"
                value={selectedSousCateId}
                onChange={(e) => setSelectedSousCateId(e.target.value)}
            >
                <option value="">-- Choisissez une sous-categorie --</option>
                {sousCategories.map((souscat)=> (
                    <option value={souscat.id} key={souscat.id}>{souscat.name}</option>
                ))}
            </select>
        </div>
    );
}

export default DependentListBetweenCatAndSousCat;

关键改动说明

  • 拆分了状态:将父分类选中值、子分类列表、子分类选中值拆分为独立状态,逻辑更清晰,避免类型冲突
  • 统一使用受控组件写法:通过value绑定选中状态,替代原生的selected属性,符合React表单开发规范
  • 新增子分类拉取逻辑封装,切换父分类时自动清空原有子分类数据,避免旧数据残留
  • 修复了子分类遍历渲染的语法问题,补充key属性,正确展示子分类名称
  • 新增异常捕获,避免接口报错导致页面功能异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 02:48:01