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

react-dropdown-tree-select组件SetState失效及重渲染异常求助

React-dropdown-tree-select 状态变更引发组件异常重渲染及报错问题解决

问题场景

使用react-dropdown-tree-select实现树形下拉框,基础功能正常,但触发状态变更时(无论是调用父组件的handleTreeUnitListChange,还是组件内部调用setState),组件出现异常重渲染,点击下拉框直接报错。环境版本:React 18.2、Node 18.15.0、NPM 9.5.0。

相关代码

树形下拉组件代码

import React, { useState, useEffect } from 'react';
import DropdownTreeSelect from 'react-dropdown-tree-select';
import 'react-dropdown-tree-select/dist/styles.css';

function TreeDropDown(props) {
  const { tree_unit_data, handleTreeUnitListChange } = props;
  const [treeData, setTreeData] = useState(tree_unit_data);

  useEffect(() => {
    // Update the treeData when tree_unit_data prop changes
    setTreeData(tree_unit_data);
  }, [tree_unit_data]);

  const onChange = (currentNode, selectedNodes) => {
    // Handle the onChange event here
    handleTreeUnitListChange(selectedNodes) // 注释此代码后组件恢复正常
  };

  return (
    <DropdownTreeSelect
      data={treeData}
      onChange={onChange}
      texts={{ placeholder: 'Select Node' }}
    />
  );
}

export default TreeDropDown;

测试用树形数据

const treeData = [
  {
    label: 'Node 1',
    children: [
      { label: 'Node 1.1' },
      {
        label: 'Node 1.2',
        children: [
          { label: 'Node 1.2.1' },
          { label: 'Node 1.2.2' },
        ],
      },
    ],
  },
  {
    label: 'Node 2',
    children: [
      { label: 'Node 2.1' },
      { label: 'Node 2.2' },
    ],
  },
];

问题原因分析

  1. 状态同步冲突:组件内部通过useState+useEffect同步父组件的tree_unit_data,同时在onChange中触发父组件状态更新,可能导致父组件重新传递新的tree_unit_data,进而触发子组件useEffect更新treeData,形成重渲染循环。
  2. 数据源与选中状态耦合:react-dropdown-tree-select内部会维护自身的选中状态,若外部修改传入的data(或data引用频繁变化),会导致组件内部状态与外部数据源不一致,引发渲染异常。
  3. React 18严格模式影响:开发环境下严格模式会双重执行生命周期方法(如useEffect),放大了状态同步的冲突问题。

解决方案

1. 移除冗余的内部状态同步

直接使用父组件传递的tree_unit_data作为数据源,无需在组件内部维护treeData状态,减少状态同步环节:

function TreeDropDown(props) {
  const { tree_unit_data, handleTreeUnitListChange } = props;

  const onChange = (currentNode, selectedNodes) => {
    handleTreeUnitListChange(selectedNodes);
  };

  return (
    <DropdownTreeSelect
      data={tree_unit_data}
      onChange={onChange}
      texts={{ placeholder: 'Select Node' }}
    />
  );
}

2. 分离数据源与选中状态

如果需要父组件控制选中状态,使用组件的selected prop传递选中节点,而非通过修改数据源来控制:

// 父组件中
import { useState, useMemo } from 'react';
import TreeDropDown from './TreeDropDown';

function ParentComponent() {
  const [selectedNodes, setSelectedNodes] = useState([]);
  // 使用useMemo保持树形数据引用稳定
  const treeData = useMemo(() => [
    // 你的树形数据
  ], []);

  return (
    <TreeDropDown
      tree_unit_data={treeData}
      selectedNodes={selectedNodes}
      handleTreeUnitListChange={setSelectedNodes}
    />
  );
}

// 子组件修改
function TreeDropDown(props) {
  const { tree_unit_data, selectedNodes, handleTreeUnitListChange } = props;

  const onChange = (currentNode, selectedNodes) => {
    handleTreeUnitListChange(selectedNodes);
  };

  return (
    <DropdownTreeSelect
      data={tree_unit_data}
      onChange={onChange}
      selected={selectedNodes}
      texts={{ placeholder: 'Select Node' }}
    />
  );
}

3. 确保数据源引用稳定

父组件中避免每次渲染都重新创建树形数据数组,使用useMemo缓存数据,防止不必要的重渲染:

const treeData = useMemo(() => [
  { /* 树形数据结构 */ },
], []); // 空依赖数组确保只初始化一次

4. 临时排查:关闭React严格模式

若问题仅出现在开发环境,可暂时关闭index.js中的严格模式(<React.StrictMode>标签),确认是否是严格模式放大了状态冲突问题,再针对性修复。

总结

核心解决思路是解耦数据源与选中状态,保持数据源引用稳定,避免不必要的状态同步循环,让react-dropdown-tree-select专注于自身的状态管理,外部仅通过onChange接收选中结果、selected控制选中状态即可。

内容的提问来源于stack exchange,提问作者Aaditya R Krishnan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 03:44:58