diff --git a/package.json b/package.json index f4dfc4d82..16020275b 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "dependencies": { "@rc-component/resize-observer": "^1.0.0", "@rc-component/trigger": "^3.0.0", - "@rc-component/util": "^1.2.1", + "@rc-component/util": "^1.3.0", "classnames": "^2.2.1", "rc-overflow": "^1.3.2" }, diff --git a/src/PickerInput/RangePicker.tsx b/src/PickerInput/RangePicker.tsx index 7a0b57839..5e6fee2cc 100644 --- a/src/PickerInput/RangePicker.tsx +++ b/src/PickerInput/RangePicker.tsx @@ -1,4 +1,4 @@ -import { useEvent, useMergedState } from '@rc-component/util'; +import { useEvent, useControlledState } from '@rc-component/util'; import cls from 'classnames'; import useLayoutEffect from '@rc-component/util/lib/hooks/useLayoutEffect'; import omit from '@rc-component/util/lib/omit'; @@ -310,9 +310,7 @@ function RangePicker( }, [showTime, activeIndex, calendarValue, activeIndexList]); // ========================= Mode ========================= - const [modes, setModes] = useMergedState<[PanelMode, PanelMode]>([picker, picker], { - value: mode, - }); + const [modes, setModes] = useControlledState<[PanelMode, PanelMode]>([picker, picker], mode); const mergedMode = modes[activeIndex] || picker; diff --git a/src/PickerInput/SinglePicker.tsx b/src/PickerInput/SinglePicker.tsx index c773fbd09..1e40be7d9 100644 --- a/src/PickerInput/SinglePicker.tsx +++ b/src/PickerInput/SinglePicker.tsx @@ -1,4 +1,4 @@ -import { useEvent, useMergedState } from '@rc-component/util'; +import { useEvent, useControlledState } from '@rc-component/util'; import cls from 'classnames'; import useLayoutEffect from '@rc-component/util/lib/hooks/useLayoutEffect'; import omit from '@rc-component/util/lib/omit'; @@ -259,9 +259,7 @@ function Picker( }; // ========================= Mode ========================= - const [mergedMode, setMode] = useMergedState(picker, { - value: mode, - }); + const [mergedMode, setMode] = useControlledState(picker, mode); /** Extends from `mergedMode` to patch `datetime` mode */ const internalMode: InternalMode = mergedMode === 'date' && showTime ? 'datetime' : mergedMode; diff --git a/src/PickerInput/hooks/useDelayState.ts b/src/PickerInput/hooks/useDelayState.ts index 6be0c127d..0904bcf0a 100644 --- a/src/PickerInput/hooks/useDelayState.ts +++ b/src/PickerInput/hooks/useDelayState.ts @@ -1,4 +1,4 @@ -import { useEvent, useMergedState } from '@rc-component/util'; +import { useEvent, useControlledState } from '@rc-component/util'; import raf from '@rc-component/util/lib/raf'; import React from 'react'; @@ -11,7 +11,15 @@ export default function useDelayState( defaultValue?: T, onChange?: (next: T) => void, ): [state: T, setState: (nextState: T, immediately?: boolean) => void] { - const [state, setState] = useMergedState(defaultValue, { value }); + const [state, setState] = useControlledState(defaultValue, value); + + // Need force update to ensure React re-render + const [, forceUpdate] = React.useState({}); + + const triggerUpdate = useEvent((nextState: T) => { + setState(nextState); + forceUpdate({}); + }); const nextValueRef = React.useRef(value); @@ -22,7 +30,7 @@ export default function useDelayState( }; const doUpdate = useEvent(() => { - setState(nextValueRef.current); + triggerUpdate(nextValueRef.current); if (onChange && state !== nextValueRef.current) { onChange(nextValueRef.current); diff --git a/src/PickerInput/hooks/useRangePickerValue.ts b/src/PickerInput/hooks/useRangePickerValue.ts index f5181f402..be21e528b 100644 --- a/src/PickerInput/hooks/useRangePickerValue.ts +++ b/src/PickerInput/hooks/useRangePickerValue.ts @@ -1,4 +1,4 @@ -import { useMergedState } from '@rc-component/util'; +import { useControlledState } from '@rc-component/util'; import useLayoutEffect from '@rc-component/util/lib/hooks/useLayoutEffect'; import * as React from 'react'; import type { GenerateConfig } from '../../generate'; @@ -72,14 +72,15 @@ export default function useRangePickerValue getDefaultPickerValue(0), - { value: startPickerValue }, + startPickerValue, ); - const [mergedEndPickerValue, setEndPickerValue] = useMergedState(() => getDefaultPickerValue(1), { - value: endPickerValue, - }); + const [mergedEndPickerValue, setEndPickerValue] = useControlledState( + () => getDefaultPickerValue(1), + endPickerValue, + ); // Current PickerValue const currentPickerValue = React.useMemo(() => { diff --git a/src/PickerInput/hooks/useRangeValue.ts b/src/PickerInput/hooks/useRangeValue.ts index 89b139d84..f7267f9d5 100644 --- a/src/PickerInput/hooks/useRangeValue.ts +++ b/src/PickerInput/hooks/useRangeValue.ts @@ -1,4 +1,4 @@ -import { useEvent, useMergedState } from '@rc-component/util'; +import { useEvent, useControlledState } from '@rc-component/util'; import * as React from 'react'; import type { GenerateConfig } from '../../generate'; import useSyncState from '../../hooks/useSyncState'; @@ -117,7 +117,7 @@ export function useInnerValue void, ) { // This is the root value which will sync with controlled or uncontrolled value - const [innerValue, setInnerValue] = useMergedState(defaultValue, { value }); + const [innerValue, setInnerValue] = useControlledState(defaultValue, value); const mergedValue = innerValue || (EMPTY_VALUE as ValueType); // ========================= Inner Values ========================= diff --git a/src/PickerPanel/index.tsx b/src/PickerPanel/index.tsx index 6dab2f3fb..e9ed18126 100644 --- a/src/PickerPanel/index.tsx +++ b/src/PickerPanel/index.tsx @@ -1,5 +1,5 @@ import classNames from 'classnames'; -import { useEvent, useMergedState, warning } from '@rc-component/util'; +import { useEvent, useControlledState, warning } from '@rc-component/util'; import * as React from 'react'; import useLocale from '../hooks/useLocale'; import { fillShowTimeConfig, getTimeProps } from '../hooks/useTimeConfig'; @@ -227,10 +227,7 @@ function PickerPanel( const now = generateConfig.getNow(); // ========================== Mode ========================== - const [mergedMode, setMergedMode] = useMergedState(picker, { - value: mode, - postState: (val) => val || 'date', - }); + const [mergedMode, setMergedMode] = useControlledState(picker || 'date', mode); const internalMode: InternalMode = mergedMode === 'date' && mergedShowTime ? 'datetime' : mergedMode; @@ -241,9 +238,7 @@ function PickerPanel( // ========================= Value ========================== // >>> Real value // Interactive with `onChange` event which only trigger when the `mode` is `picker` - const [innerValue, setMergedValue] = useMergedState(defaultValue, { - value, - }); + const [innerValue, setMergedValue] = useControlledState(defaultValue, value); const mergedValue = React.useMemo(() => { // Clean up `[null]` @@ -282,11 +277,9 @@ function PickerPanel( // >>> PickerValue // PickerValue is used to control the current displaying panel - const [mergedPickerValue, setInternalPickerValue] = useMergedState( + const [mergedPickerValue, setInternalPickerValue] = useControlledState( defaultPickerValue || mergedValue[0] || now, - { - value: pickerValue, - }, + pickerValue, ); React.useEffect(() => {