Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions docs/examples/range.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,19 @@ export default () => {
disabledDate={disabledDate}
/>
</div>
<div>
<h3>needConfirm is false</h3>
<RangePicker<Moment>
{...sharedProps}
value={undefined}
locale={zhCN}
needConfirm={false}
picker="time"
ranges={{
test: [moment(), moment().add(1, 'hour')],
}}
/>
</div>
</div>
</div>
);
Expand Down
24 changes: 20 additions & 4 deletions src/PickerInput/Popup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export interface PopupProps<DateType extends object = any, PresetValue = DateTyp
activeInfo?: [activeInputLeft: number, activeInputRight: number, selectorWidth: number];
// Direction
direction?: 'ltr' | 'rtl';
/** @internal: active input index for layout retry. Not part of public API. */
index?: number;

// Fill
/** TimePicker or showTime only */
Expand All @@ -58,7 +60,7 @@ export default function Popup<DateType extends object = any>(props: PopupProps<D
range,
multiple,
activeInfo = [0, 0, 0],

index = 0,
// Presets
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

避免将内部属性 index 透传到子组件/DOM

当前仍以 {...props} 透传给 <PopupPanel><Footer>,可能让未知 prop(index)一路落到 DOM,触发 React “Unknown prop” 警告或影响 SSR 对齐。建议在本组件消费掉 index,并显式排除后再下发。

在本段解构保持不变的前提下,新增一个“去除 index 的转发 props”,并替换两处传参:

// 紧跟解构之后添加
const forwardProps = React.useMemo(() => {
  const { index: _internalIndex, ...rest } = props;
  return rest as Omit<PopupProps<DateType>, 'index'>;
}, [props]);

然后将下方两处替换为:

- <PopupPanel {...props} value={popupPanelValue} />
+ <PopupPanel {...forwardProps} value={popupPanelValue} />

- <Footer
-   {...props}
+ <Footer
+   {...forwardProps}
    showNow={multiple ? false : showNow}
    invalid={disableSubmit}
    onSubmit={onFooterSubmit}
  />
🤖 Prompt for AI Agents
In src/PickerInput/Popup/index.tsx around lines 63-64, avoid forwarding the
internal prop `index` to child components: consume `index` locally and create a
memoized `forwardProps` that omits `index` (e.g. using object rest to strip
`index` and casting to the appropriate Omit type), then replace `{...props}`
with `{...forwardProps}` when rendering <PopupPanel> and <Footer> so the
internal `index` does not propagate to DOM/children.

presets,
onPresetHover,
Expand All @@ -80,7 +82,6 @@ export default function Popup<DateType extends object = any>(props: PopupProps<D
onOk,
onSubmit,
} = props;

const { prefixCls } = React.useContext(PickerContext);
const panelPrefixCls = `${prefixCls}-panel`;

Expand Down Expand Up @@ -118,7 +119,13 @@ export default function Popup<DateType extends object = any>(props: PopupProps<D
// Arrow Offset
const wrapperRect = wrapperRef.current.getBoundingClientRect();
if (!wrapperRect.height || wrapperRect.right < 0) {
setRetryTimes((times) => Math.max(0, times - 1));
// This is a workaround to bypass the inconsistent useEffect behavior in React 18.
// When wrapperRef.current.getBoundingClientRect() fails to calculate the position correctly, it enters the retry logic.
// Under normal circumstances, retryTimes - 1 should equal 9, and useEffect would re-execute the side effect if dependencies change.
// However, in React 18, the side effect is no longer re-executed in such cases.
// By subtracting the index of the currently active input field (index, which is either 0 or 1), we compensate for this additional execution.
// Related issue: https://github.com/ant-design/ant-design/issues/54885
setRetryTimes((times) => Math.max(0, times - index - 1));
return;
}

Expand All @@ -138,7 +145,16 @@ export default function Popup<DateType extends object = any>(props: PopupProps<D
setContainerOffset(0);
}
}
}, [retryTimes, rtl, containerWidth, activeInputLeft, activeInputRight, selectorWidth, range]);
}, [
retryTimes,
rtl,
containerWidth,
activeInputLeft,
activeInputRight,
selectorWidth,
range,
index,
]);

// ======================== Custom ========================
function filterEmpty<T>(list: T[]) {
Expand Down
1 change: 1 addition & 0 deletions src/PickerInput/RangePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,7 @@ function RangePicker<DateType extends object = any>(
range
multiplePanel={multiplePanel}
activeInfo={activeInfo}
index={activeIndex}
// Disabled
disabledDate={mergedDisabledDate}
// Focus
Expand Down
1 change: 1 addition & 0 deletions src/PickerInput/SinglePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,7 @@ function Picker<DateType extends object = any>(
// Focus
onFocus={onPanelFocus}
onBlur={onSharedBlur}
index={activeIndex}
// Mode
picker={picker}
mode={mergedMode}
Expand Down