Browse Source

fix: [Cascader] checked value will be unexpectedly cleared in multiple mode when treeData was updated #622 (#634)

fix:  [Cascader] checked value will be unexpectedly cleared in multiple mode when treeData was updated #622

Co-authored-by: chenyuling <[email protected]>
boomboomchen 3 years ago
parent
commit
f9912e69c5

+ 24 - 0
packages/semi-ui/cascader/__test__/cascader.test.js

@@ -195,6 +195,30 @@ describe('Cascader', () => {
         // done();
     });
 
+    it('dynamic treeData in multiple and uncontrolled mode', () => {
+        const cascader = render({
+            defaultValue: 'Yazhou',
+            multiple: true,
+        });
+        const opt = document.querySelectorAll(`.${BASE_CLASS_PREFIX}-cascader-selection-multiple .${BASE_CLASS_PREFIX}-tag`);
+        expect(opt.length).toEqual(1);
+        cascader.setProps({ treeData: treeDataWithDisabled });
+        cascader.update();
+        expect(opt.length).toEqual(1);
+    });
+
+    it('dynamic treeData in multiple and controlled mode', () => {
+        const cascader = render({
+            value: 'Yazhou',
+            multiple: true,
+        });
+        const opt = document.querySelectorAll(`.${BASE_CLASS_PREFIX}-cascader-selection-multiple .${BASE_CLASS_PREFIX}-tag`);
+        expect(opt.length).toEqual(1);
+        cascader.setProps({ treeData: treeDataWithDisabled });
+        cascader.update();
+        expect(opt.length).toEqual(1);
+    });
+
     it('getPopupContainer', () => {
         let cascader = render({
             getPopupContainer: getPopupContainer,

+ 73 - 0
packages/semi-ui/cascader/_story/cascader.stories.js

@@ -1348,4 +1348,77 @@ export const LeafOnly = () => {
           />
       </div>
   );
+}
+
+export const DynamicTreeData = () => {
+  const [treeDataDemo1,setTreeData1]=useState(treeData2);
+  const [treeDataDemo2,setTreeData2]=useState(treeData2);
+  const [treeDataDemo3,setTreeData3]=useState(treeData2);
+  const [treeDataDemo4,setTreeData4]=useState(treeData2);
+  const [treeDataDemo5,setTreeData5]=useState(treeData2);
+  const [value3,setValue3]=useState();
+  const [value4,setValue4]=useState();
+  return (
+      <div>
+          <div>多选 + 动态更新 tree</div>
+          <Cascader
+            style={{ width: 300 }}
+            treeData={treeDataDemo1}
+            multiple 
+            placeholder="请选择所在地区"
+          />
+          <Button onClick={()=>{setTreeData1(treeData3)}}>改变treeData</Button>
+          <br />
+          <br />
+          <div>单选 + 动态更新 tree</div>
+          <Cascader
+            style={{ width: 300 }}
+            treeData={treeDataDemo2}
+            placeholder="请选择所在地区"
+          />
+          <Button onClick={()=>{setTreeData2(treeData3)}}>改变treeData</Button>
+          <br />
+          <br />
+          <div>多选 + 动态更新 tree + 受控</div>
+          <Cascader
+            style={{ width: 300 }}
+            treeData={treeDataDemo3}
+            multiple
+            value={value3}
+            onChange={v=>{
+              console.log(v);
+              setValue3(v);
+            }}
+            placeholder="请选择所在地区"
+          />
+          <Button onClick={()=>{setTreeData3(treeData3)}}>改变treeData</Button>
+          <br />
+          <br />
+          <div>单选 + 动态更新 tree + 受控</div>
+          <Cascader
+            style={{ width: 300 }}
+            treeData={treeDataDemo4}
+            value={value4}
+            onChange={v=>{
+              console.log(v);
+              setValue4(v);
+            }}
+            placeholder="请选择所在地区"
+          />
+          <Button onClick={()=>{setTreeData4(treeData3)}}>改变treeData</Button>
+          <br />
+          <br />
+          <div>多选 + 动态更新 tree + defaultValue 为亚洲</div>
+          <Cascader
+            style={{ width: 300 }}
+            treeData={treeDataDemo5}
+            multiple
+            defaultValue='yazhou'
+            placeholder="请选择所在地区"
+          />
+          <Button onClick={()=>{setTreeData5(treeData3)}}>改变treeData</Button>
+          <br />
+          <br />
+      </div>
+  );
 }

+ 5 - 2
packages/semi-ui/cascader/index.tsx

@@ -14,7 +14,7 @@ import CascaderFoundation, {
 } from '@douyinfe/semi-foundation/cascader/foundation';
 import { cssClasses, strings } from '@douyinfe/semi-foundation/cascader/constants';
 import { numbers as popoverNumbers } from '@douyinfe/semi-foundation/popover/constants';
-import { isEqual, isString, isEmpty, isFunction, isNumber, noop, flatten } from 'lodash';
+import { isSet, isEqual, isString, isEmpty, isFunction, isNumber, noop, flatten } from 'lodash';
 import '@douyinfe/semi-foundation/cascader/cascader.scss';
 import { IconClear, IconChevronDown } from '@douyinfe/semi-icons';
 import { findKeysForValues, convertDataToEntities, calcMergeType } from '@douyinfe/semi-foundation/cascader/util';
@@ -426,7 +426,10 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
                     });
                     realKeys = formatKeys;
                 }
-                const calRes = calcCheckedKeys(flatten(realKeys as string[]), keyEntities);
+                if (isSet(realKeys)) {
+                    realKeys = [...realKeys];
+                }
+                const calRes = calcCheckedKeys(flatten(realKeys), keyEntities);
                 const checkedKeys = new Set(calRes.checkedKeys);
                 const halfCheckedKeys = new Set(calRes.halfCheckedKeys);
                 // disableStrictly