Przeglądaj źródła

fix: [Tree] value does not affect node expansion when treeData/treeDataSimpleJson is updated #257 (#645)

Co-authored-by: chenyuling <[email protected]>
boomboomchen 3 lat temu
rodzic
commit
e59aebc1a2

+ 87 - 2
packages/semi-ui/tree/__test__/tree.test.js

@@ -1,6 +1,7 @@
-import { Tree, Icon } from '../../index';
-import { BASE_CLASS_PREFIX } from '../../../semi-foundation/base/constants';
+import { isEqual } from 'lodash';
 import { IconMapPin } from '@douyinfe/semi-icons';
+import { BASE_CLASS_PREFIX } from '../../../semi-foundation/base/constants';
+import { Tree, Button } from '../../index';
 
 const treeChildren = [
     {
@@ -672,6 +673,90 @@ describe('Tree', () => {
         expect(tree.state().selectedKeys.length).toEqual(0);
     });
 
+
+    /**
+     * Detect whether the expanded item will be expanded according to the value when the value
+     *  or treeData is changed, when expandedKeys is not controlled
+     */
+     const treeJsonData1 = {
+        "Node0": {
+            "Child Node0-0": '0-0',
+            "Child Node0-1": '0-1',
+        },
+        "Node1": {
+            "Child Node1-0": '1-0',
+            "Child Node1-1": '1-1',
+        }
+    };
+    const treeJsonData2 = {
+        "Updated Node0": { 
+            "Updated Child Node0-0": {
+                'Updated Child Node0-0-0':'0-0'
+            }, 
+            "Updated Child Node0-1": '0-1', 
+        },
+        "Updated Node1": { 
+            "Updated Child Node1-0": '1-0', 
+            "Updated Child Node1-1": '1-1', 
+        }
+    };
+
+    it('expandedKeys when treeDataSimpleJson update', () => {
+        const tree = mount(
+            <Tree
+                value='0-0'
+                multiple
+                treeDataSimpleJson={treeJsonData1}
+            />,
+            {
+                attachTo: document.getElementById('container')
+            }
+        );
+        const treeDataButton = mount(
+            <Button
+                onClick={() => {
+                    if (isEqual(tree.props().treeDataSimpleJson, treeJsonData1)) {
+                        tree.setProps({ treeDataSimpleJson: treeJsonData2 });
+                        tree.update();
+                    } else {
+                        tree.setProps({ treeDataSimpleJson: treeJsonData1 });
+                        tree.update();
+                    }
+                }}
+            >
+                update treeData
+            </Button>
+        );
+        expect(
+            tree
+            .find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`)
+            .at(0)
+            .hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)
+        ).toEqual(false);
+        expect(
+            tree
+            .find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-2`)
+            .at(0)
+            .hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)
+        ).toEqual(true);
+        expect(
+            tree
+            .find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-1`)
+            .at(1)
+            .hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)
+        ).toEqual(true);
+        treeDataButton.simulate('click');
+        expect(
+            tree
+            .find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-2`)
+            .at(0)
+            .hasClass(`${BASE_CLASS_PREFIX}-tree-option-collapsed`)
+        ).toEqual(false);
+        treeDataButton.simulate('click');
+        tree.unmount();
+        treeDataButton.unmount();
+    });
+
     it('expandAction = false / default behavior', () => {
         const nativeEvent = { nativeEvent: { stopImmediatePropagation: () => { } } }
         let spyOnExpand = sinon.spy(() => { });

+ 65 - 5
packages/semi-ui/tree/_story/tree.stories.js

@@ -1,12 +1,11 @@
 import React, { useRef, useState } from 'react';
+import { cloneDeep, difference, isEqual } from 'lodash';
+import { IconEdit, IconMapPin, IconMore } from '@douyinfe/semi-icons';
 import Tree from '../index';
 import AutoSizer from '../autoSizer';
-import { Button, ButtonGroup, Input, Popover, Toast } from '../../index';
+import { Button, ButtonGroup, Input, Popover, Toast, Space } from '../../index';
 import BigTree from './BigData';
 import testData from './data';
-import { cloneDeep, difference, isEqual } from 'lodash';
-import { IconEdit, IconMapPin, IconMore } from '@douyinfe/semi-icons';
-
 const TreeNode = Tree.TreeNode;
 
 export default {
@@ -2338,4 +2337,65 @@ export const CheckRelationDemo = () => {
       />
     </>
   );
-};
+};
+
+export const ValueImpactExpansionWithDynamicTreeData = () => {
+  const json = {
+      "Node0": { 
+          "Child Node0-0": '0-0', 
+          "Child Node0-1": '0-1', 
+      },
+      "Node1": { 
+          "Child Node1-0": '1-0', 
+          "Child Node1-1": '1-1', 
+      }
+  }
+  const json2 = {
+      "Updated Node0": { 
+          "Updated Child Node0-0": {
+              'Updated Child Node0-0-0':'0-0'
+          }, 
+          "Updated Child Node0-1": '0-1', 
+      },
+      "Updated Node1": { 
+          "Updated Child Node1-0": '1-0', 
+          "Updated Child Node1-1": '1-1', 
+      }
+  }
+  const style = {
+      width: 260,
+      height: 420,
+      border: '1px solid var(--color-border)'
+  }
+  const [value, setValue] = useState('0-0')
+  const [tree, setTree] = useState(json);
+  const handleValueButtonClick = () => {
+      if (value === '0-0') {
+          setValue('1-0');
+      } else {
+          setValue('0-0');
+      }
+  }
+  const handleTreeDataButtonClick = () => {
+      if(isEqual(tree, json)){
+          setTree(json2);
+      } else {
+          setTree(json);
+      }
+  }
+  return (  
+    <>
+      <div>value 受控时,当 treeData/treeDataSimpleJson 改变时,应该根据 value 自动展开</div>
+      <Tree 
+          value={value}
+          treeDataSimpleJson={tree} 
+          style={style}
+          onChange={v => setValue(v)}
+      />
+      <Space>
+          <Button onClick={handleValueButtonClick}>改变 value</Button>
+          <Button onClick={handleTreeDataButtonClick}>改变 TreeData</Button>    
+      </Space>
+    </>
+  )
+}

+ 4 - 2
packages/semi-ui/tree/index.tsx

@@ -192,6 +192,7 @@ class Tree extends BaseComponent<TreeProps, TreeState> {
         const newState: Partial<TreeState> = {
             prevProps: props,
         };
+        const isExpandControlled = 'expandedKeys' in props;
 
         // Accept a props field as a parameter to determine whether to update the field
         const needUpdate = (name: string) => {
@@ -239,7 +240,8 @@ class Tree extends BaseComponent<TreeProps, TreeState> {
                 newState.motionType = null;
             }
         }
-        const expandAllWhenDataChange = (needUpdate('treeDataSimpleJson') || needUpdate('treeData')) && props.expandAll;
+        const dataUpdated = needUpdate('treeDataSimpleJson') || needUpdate('treeData');
+        const expandAllWhenDataChange = dataUpdated && props.expandAll;
         if (!isSeaching) {
             // Update expandedKeys
             if (needUpdate('expandedKeys') || (prevProps && needUpdate('autoExpandParent'))) {
@@ -273,7 +275,7 @@ class Tree extends BaseComponent<TreeProps, TreeState> {
                     props.multiple,
                     valueEntities
                 );
-            } else if (!prevProps && props.value) {
+            } else if ((!prevProps || (!isExpandControlled && dataUpdated)) && props.value) {
                 newState.expandedKeys = calcExpandedKeysForValues(
                     props.value,
                     keyEntities,