From 1c6b29fa2f06316d364640a2573268eaa5a00748 Mon Sep 17 00:00:00 2001 From: Wanpan Date: Tue, 12 Mar 2024 02:16:59 +0800 Subject: [PATCH 1/5] fix: long label panel position abnormal --- src/OptionList/useActive.ts | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/OptionList/useActive.ts b/src/OptionList/useActive.ts index 7bf02724..68fe3bb9 100644 --- a/src/OptionList/useActive.ts +++ b/src/OptionList/useActive.ts @@ -16,16 +16,17 @@ export default ( // This also control the open status const [activeValueCells, setActiveValueCells] = React.useState([]); - React.useEffect( - () => { - if (open && !multiple) { - setActiveValueCells(firstValueCells || []); - } - }, - /* eslint-disable react-hooks/exhaustive-deps */ - [open, firstValueCells], - /* eslint-enable react-hooks/exhaustive-deps */ - ); + // use useLayoutEffect Prevent flickering + React.useLayoutEffect(() => { + if (open && !multiple) { + setActiveValueCells(firstValueCells || []); + // no values run reset activeValueCells + } else if (values.length === 0) { + setActiveValueCells([]); + } + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [open, firstValueCells]); return [activeValueCells, setActiveValueCells]; }; From 23767d95e117d01c6ec4b2372965a4d4247946a2 Mon Sep 17 00:00:00 2001 From: Wanpan Date: Tue, 12 Mar 2024 12:51:58 +0800 Subject: [PATCH 2/5] fix: optimized reset activeValueCells logic --- src/OptionList/useActive.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/OptionList/useActive.ts b/src/OptionList/useActive.ts index 68fe3bb9..8a6b3826 100644 --- a/src/OptionList/useActive.ts +++ b/src/OptionList/useActive.ts @@ -11,20 +11,27 @@ export default ( const { values } = React.useContext(CascaderContext); const firstValueCells = values[0]; + const lastValuesRef = React.useRef(null); // Record current dropdown active options // This also control the open status const [activeValueCells, setActiveValueCells] = React.useState([]); - // use useLayoutEffect Prevent flickering + // use useLayoutEffect timely update of DOM calculation position and Prevent flickering React.useLayoutEffect(() => { if (open && !multiple) { - setActiveValueCells(firstValueCells || []); - // no values run reset activeValueCells - } else if (values.length === 0) { - setActiveValueCells([]); + // firstValueCells clear use delay update + if (lastValuesRef.current && !firstValueCells) { + setTimeout(() => { + setActiveValueCells([]); + }, 0); + } else { + setActiveValueCells(firstValueCells || []); + } } + lastValuesRef.current = firstValueCells; + // eslint-disable-next-line react-hooks/exhaustive-deps }, [open, firstValueCells]); From 7929d5537e153aa0b1bb3a3e9b855f8af1985258 Mon Sep 17 00:00:00 2001 From: Wanpan Date: Fri, 29 Mar 2024 13:56:45 +0800 Subject: [PATCH 3/5] fix: optimized reset logic --- src/OptionList/useActive.ts | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/OptionList/useActive.ts b/src/OptionList/useActive.ts index 8a6b3826..4eaf4f0a 100644 --- a/src/OptionList/useActive.ts +++ b/src/OptionList/useActive.ts @@ -11,29 +11,21 @@ export default ( const { values } = React.useContext(CascaderContext); const firstValueCells = values[0]; - const lastValuesRef = React.useRef(null); // Record current dropdown active options // This also control the open status const [activeValueCells, setActiveValueCells] = React.useState([]); - // use useLayoutEffect timely update of DOM calculation position and Prevent flickering - React.useLayoutEffect(() => { - if (open && !multiple) { - // firstValueCells clear use delay update - if (lastValuesRef.current && !firstValueCells) { - setTimeout(() => { - setActiveValueCells([]); - }, 0); - } else { - setActiveValueCells(firstValueCells || []); + React.useEffect( + () => { + if (!multiple) { + setActiveValueCells(open || firstValueCells ? firstValueCells || [] : []); } - } - - lastValuesRef.current = firstValueCells; - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [open, firstValueCells]); + }, + /* eslint-disable react-hooks/exhaustive-deps */ + [open, firstValueCells], + /* eslint-enable react-hooks/exhaustive-deps */ + ); return [activeValueCells, setActiveValueCells]; }; From 8f214e5967d978cfc6e8d1d1921d5318d2a1f637 Mon Sep 17 00:00:00 2001 From: Wanpan Date: Sun, 7 Apr 2024 22:25:28 +0800 Subject: [PATCH 4/5] fix: Simplify the logic --- src/OptionList/useActive.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OptionList/useActive.ts b/src/OptionList/useActive.ts index 4eaf4f0a..849f9bfb 100644 --- a/src/OptionList/useActive.ts +++ b/src/OptionList/useActive.ts @@ -19,7 +19,7 @@ export default ( React.useEffect( () => { if (!multiple) { - setActiveValueCells(open || firstValueCells ? firstValueCells || [] : []); + setActiveValueCells(firstValueCells || []); } }, /* eslint-disable react-hooks/exhaustive-deps */ From 4703b0417702df12ae1060f4851cfcbc5abd33d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Mon, 8 Apr 2024 22:57:16 +0800 Subject: [PATCH 5/5] test: add test case --- tests/selector.spec.tsx | 44 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/tests/selector.spec.tsx b/tests/selector.spec.tsx index 3b20e6c9..840ca194 100644 --- a/tests/selector.spec.tsx +++ b/tests/selector.spec.tsx @@ -1,18 +1,58 @@ import React, { useState } from 'react'; +import { fireEvent, render } from '@testing-library/react'; import { mount } from './enzyme'; import Cascader from '../src'; import { addressOptions } from './demoOptions'; +// Mock `useActive` hook +jest.mock('../src/OptionList/useActive', () => (multiple: boolean, open: boolean) => { + // Pass to origin hooks + const originHook = jest.requireActual('../src/OptionList/useActive').default; + const [activeValueCells, setActiveValueCells] = originHook(multiple, open); + + global.activeValueCells = activeValueCells; + + return [activeValueCells, setActiveValueCells]; +}); + describe('Cascader.Selector', () => { describe('clear all', () => { it('single', () => { const onChange = jest.fn(); - const wrapper = mount(); + const { container } = render( + , + ); - wrapper.find('.rc-cascader-clear-icon').simulate('mouseDown'); + fireEvent.mouseDown(container.querySelector('.rc-cascader-clear-icon')); expect(onChange).toHaveBeenCalledWith(undefined, undefined); }); + it('Should clear activeCells', () => { + const onChange = jest.fn(); + + const { container } = render( + , + ); + + // Open and select + fireEvent.mouseDown(container.querySelector('.rc-cascader-selector')); + expect(container.querySelector('.rc-cascader-open')).toBeTruthy(); + + fireEvent.click(container.querySelector('.rc-cascader-menu-item-content')); + fireEvent.click(container.querySelectorAll('.rc-cascader-menu-item-content')[1]); + expect(container.querySelector('.rc-cascader-open')).toBeFalsy(); + + // Clear + fireEvent.mouseDown(container.querySelector('.rc-cascader-clear-icon')); + expect(global.activeValueCells).toEqual([]); + }); + it('multiple', () => { const onChange = jest.fn(); const wrapper = mount(