1- import React , { ElementType , forwardRef , HTMLAttributes , useEffect , useRef , useState } from 'react'
1+ import React , {
2+ ElementType ,
3+ forwardRef ,
4+ HTMLAttributes ,
5+ useCallback ,
6+ useEffect ,
7+ useMemo ,
8+ useRef ,
9+ useState ,
10+ } from 'react'
211import PropTypes from 'prop-types'
312import classNames from 'classnames'
413import type { Options } from '@popperjs/core'
@@ -190,59 +199,63 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
190199 ref
191200 ) => {
192201 const dropdownRef = useRef < HTMLDivElement > ( null )
193- const dropdownToggleRef = useRef < HTMLElement > ( null )
194202 const dropdownMenuRef = useRef < HTMLDivElement | HTMLUListElement > ( null )
195203 const forkedRef = useForkedRef ( ref , dropdownRef )
204+ const [ dropdownToggleElement , setDropdownToggleElement ] = useState < HTMLElement | null > ( null )
196205 const [ _visible , setVisible ] = useState ( visible )
197206 const { initPopper, destroyPopper } = usePopper ( )
198207
199- const Component = variant === 'nav-item' ? 'li' : as
208+ const dropdownToggleRef = useCallback ( ( node : HTMLElement | null ) => {
209+ if ( node ) {
210+ setDropdownToggleElement ( node )
211+ }
212+ } , [ ] )
200213
201- // Disable popper if responsive aligment is set.
202- if ( typeof alignment === 'object' ) {
203- popper = false
204- }
214+ const allowPopperUse = popper && typeof alignment !== 'object'
215+ const Component = variant === 'nav-item' ? 'li' : as
205216
206217 const contextValues = {
207218 alignment,
208219 container,
209220 dark,
210- dropdownToggleRef,
211221 dropdownMenuRef,
212- popper,
222+ dropdownToggleRef,
223+ popper : allowPopperUse ,
213224 portal,
214225 variant,
215226 visible : _visible ,
216227 setVisible,
217228 }
218229
219- const defaultPopperConfig = {
220- modifiers : [
221- {
222- name : 'offset' ,
223- options : {
224- offset : offset ,
230+ const computedPopperConfig : Partial < Options > = useMemo ( ( ) => {
231+ const defaultPopperConfig = {
232+ modifiers : [
233+ {
234+ name : 'offset' ,
235+ options : {
236+ offset,
237+ } ,
225238 } ,
226- } ,
227- ] ,
228- placement : getPlacement ( placement , direction , alignment , isRTL ( dropdownMenuRef . current ) ) ,
229- }
239+ ] ,
240+ placement : getPlacement ( placement , direction , alignment , isRTL ( dropdownMenuRef . current ) ) ,
241+ }
230242
231- const computedPopperConfig : Partial < Options > = {
232- ...defaultPopperConfig ,
233- ...( typeof popperConfig === 'function' ? popperConfig ( defaultPopperConfig ) : popperConfig ) ,
234- }
243+ return {
244+ ...defaultPopperConfig ,
245+ ...( typeof popperConfig === 'function' ? popperConfig ( defaultPopperConfig ) : popperConfig ) ,
246+ }
247+ } , [ offset , placement , direction , alignment , popperConfig ] )
235248
236249 useEffect ( ( ) => {
237250 setVisible ( visible )
238251 } , [ visible ] )
239252
240253 useEffect ( ( ) => {
241- const toggleElement = dropdownToggleRef . current
254+ const toggleElement = dropdownToggleElement
242255 const menuElement = dropdownMenuRef . current
243256
244257 if ( _visible && toggleElement && menuElement ) {
245- if ( popper ) {
258+ if ( allowPopperUse ) {
246259 initPopper ( toggleElement , menuElement , computedPopperConfig )
247260 }
248261
@@ -257,7 +270,7 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
257270 }
258271
259272 return ( ) => {
260- if ( popper ) {
273+ if ( allowPopperUse ) {
261274 destroyPopper ( )
262275 }
263276
@@ -269,14 +282,7 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
269282
270283 onHide ?.( )
271284 }
272- } , [
273- computedPopperConfig ,
274- destroyPopper ,
275- dropdownMenuRef ,
276- dropdownToggleRef ,
277- initPopper ,
278- _visible ,
279- ] )
285+ } , [ dropdownToggleElement , _visible ] )
280286
281287 const handleKeydown = ( event : KeyboardEvent ) => {
282288 if (
@@ -304,11 +310,11 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
304310 }
305311
306312 const handleMouseUp = ( event : Event ) => {
307- if ( ! dropdownToggleRef . current || ! dropdownMenuRef . current ) {
313+ if ( ! dropdownToggleElement || ! dropdownMenuRef . current ) {
308314 return
309315 }
310316
311- if ( dropdownToggleRef . current . contains ( event . target as HTMLElement ) ) {
317+ if ( dropdownToggleElement . contains ( event . target as HTMLElement ) ) {
312318 return
313319 }
314320
0 commit comments