@@ -33,6 +33,7 @@ export type {
3333} ;
3434
3535import UniqueProvider , { type UniqueProviderProps } from './UniqueProvider' ;
36+ import { useControlledState } from '@rc-component/util' ;
3637
3738export { UniqueProvider } ;
3839export type { UniqueProviderProps } ;
@@ -303,12 +304,12 @@ export function generateTrigger(
303304 : null ;
304305
305306 // ============================ Open ============================
306- const [ internalOpen , setInternalOpen ] = React . useState (
307+ const [ internalOpen , setInternalOpen ] = useControlledState (
307308 defaultPopupVisible || false ,
309+ popupVisible ,
308310 ) ;
309311
310- // Render still use props as first priority
311- const mergedOpen = popupVisible ?? internalOpen ;
312+ const mergedOpen = internalOpen || false ;
312313
313314 // ========================== Children ==========================
314315 const child = React . useMemo ( ( ) => {
@@ -321,20 +322,9 @@ export function generateTrigger(
321322
322323 const originChildProps = child ?. props || { } ;
323324
324- // We use effect sync here in case `popupVisible` back to `undefined`
325- const setMergedOpen = useEvent ( ( nextOpen : boolean ) => {
326- if ( openUncontrolled ) {
327- setInternalOpen ( nextOpen ) ;
328- }
329- } ) ;
330-
331325 // Support ref
332326 const isOpen = useEvent ( ( ) => mergedOpen ) ;
333327
334- useLayoutEffect ( ( ) => {
335- setInternalOpen ( popupVisible || false ) ;
336- } , [ popupVisible ] ) ;
337-
338328 // Extract common options for UniqueProvider
339329 const getUniqueOptions = useEvent ( ( delay : number = 0 ) => ( {
340330 popup,
@@ -385,7 +375,7 @@ export function generateTrigger(
385375 lastTriggerRef . current = [ ] ;
386376
387377 const internalTriggerOpen = useEvent ( ( nextOpen : boolean ) => {
388- setMergedOpen ( nextOpen ) ;
378+ setInternalOpen ( nextOpen ) ;
389379
390380 // Enter or Pointer will both trigger open state change
391381 // We only need take one to avoid duplicated change event trigger
0 commit comments