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

React组件重渲染后保持下拉列表展开状态的方案咨询

解决方案:保持删除后子列表的展开状态

这个问题的核心原因很明确:listarProdutosItens组件的openProd状态是组件内部的局部状态,当你删除数据后调用fetchLista重新拉取数据,父组件AdmControls的tipos状态更新,会触发listarProdutos重新渲染,进而导致所有listarProdutosItens组件重新初始化——它们的useState(false)会再次执行,所以被删除项所在的子列表就会收起。

要解决这个问题,我们需要把子列表的展开状态提升到更上层的组件(比如listarProdutos),让状态脱离单个listarProdutosItens的生命周期,这样即使子组件重新渲染,状态也能被保留。

具体修改步骤

1. 修改listarProdutos组件,管理所有子列表的展开状态

把原来每个listarProdutosItens的openProd状态,改成由父组件用一个对象来管理,键是子列表的唯一标识(这里用子列表的标题itemTitulo就很合适),值是布尔值表示是否展开。

const listarProdutos = props => { 
    const [open, setOpen] = React.useState(false);
    // 新增:管理所有子列表的展开状态,初始为空对象
    const [openProdStates, setOpenProdStates] = React.useState({});

    // 新增:切换指定子列表的展开状态
    const toggleOpenProd = (titulo) => {
        setOpenProdStates(prev => ({
            ...prev,
            [titulo]: !prev[titulo]
        }));
    };

    return ( 
        <div> 
            <h1 style={{color: 'red'}} onClick={() => setOpen(!open)} >LISTA</h1> 
            { open ? props.produtosLista.map((item, i) => (
                <ListarProdutosItens 
                    listaItens={item} 
                    key={item+i} 
                    fetchLista={props.fetchLista}
                    // 传递当前子列表的展开状态和切换函数
                    isOpen={openProdStates[item[0].titulo] || false}
                    toggleOpen={() => toggleOpenProd(item[0].titulo)}
                />
            )) : null} 
        </div> 
    ) 
}

2. 修改listarProdutosItens组件,使用父组件传递的状态

去掉组件内部的useState,改用父组件传入的isOpen和toggleOpen来控制展开状态:

const listarProdutosItens = props => { 
    // 移除原来的局部状态:const [openProd, setOpenProd] = React.useState(false);
    let itemTitulo = props.listaItens[0].titulo; 
    const excluirItemHandler = i => { 
        let key = props.listaItens[i].key; 
        let categoria = props.listaItens[i].categoria; 
        axios.delete(`/adm/${categoria}/${key}.json`) 
        .then(res => props.fetchLista()) 
        .catch(error => console.log(error)) 
    } 
    return ( 
        <div> 
            {/* 改用父组件的toggleOpen函数 */}
            <h2 onClick={props.toggleOpen} >{itemTitulo}</h2> 
            {/* 改用父组件传递的isOpen状态 */}
            {props.isOpen ? <table> 
                <thead> 
                    <tr> 
                        <th>Nome</th> 
                        <th>Valor</th> 
                        { itemTitulo === 'Tipo de Acabamento Pia' || itemTitulo === 'Tipo de Rodopia' || itemTitulo === 'Tipo de Acabamento Seco' ? <th>Altura</th> : null } 
                        {itemTitulo === 'Tipo de Cuba' ? <th>Furo</th> : null} 
                    </tr> 
                </thead> 
                {props.listaItens.map((it, i) => { 
                    return ( 
                        i !== 0 ? <thead key={it+i}> 
                            <tr> 
                                <td>{it.nome}</td> 
                                <td>{it.valor}</td> 
                                { itemTitulo === 'Tipo de Acabamento Pia' || itemTitulo === 'Tipo de Rodopia' || itemTitulo === 'Tipo de Acabamento Seco' ? <td>{it.altura}</td> : null } 
                                {itemTitulo === 'Tipo de Cuba' ? <td>{it.furo}</td> : null} 
                                <td><button onClick={() => excluirItemHandler(i)} >Excluir</button></td> 
                            </tr> 
                        </thead> : null 
                    ) 
                })} 
            </table> : null} 
        </div> 
    ) 
}

为什么这样修改有效?

  • 子列表的展开状态现在由listarProdutos组件管理,而不是每个listarProdutosItens自己持有。即使删除数据后重新拉取,listarProdutos的openProdStates状态不会被重置,只有当用户手动点击切换时才会改变。
  • 每个子列表通过唯一的标题itemTitulo来绑定自己的展开状态,确保多个子列表的状态不会互相干扰。
  • 这种方式符合React的状态提升原则:当多个组件需要共享状态或者状态需要在组件重新渲染时保留,就把状态提升到它们的共同父组件中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 15:43:12