From 4ef57a3db113e359f2dbad12f85a2cb91c5de2cb Mon Sep 17 00:00:00 2001 From: 3lang <675483520@qq.com> Date: Mon, 1 Aug 2022 22:46:37 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20`popover`=20?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E6=89=93=E5=BC=80=E9=97=AE=E9=A2=98=20close?= =?UTF-8?q?=20#540=20(#541)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/hooks/use-lazy-effect.ts | 15 ++ .../src/components/popover/Popover.tsx | 136 ++++++++++-------- 2 files changed, 88 insertions(+), 63 deletions(-) create mode 100644 packages/react-vant/src/components/hooks/use-lazy-effect.ts diff --git a/packages/react-vant/src/components/hooks/use-lazy-effect.ts b/packages/react-vant/src/components/hooks/use-lazy-effect.ts new file mode 100644 index 000000000..f5b308385 --- /dev/null +++ b/packages/react-vant/src/components/hooks/use-lazy-effect.ts @@ -0,0 +1,15 @@ +import { useEffect, useState } from 'react' + +const useLazyEffect: typeof useEffect = (effect, deps) => { + const [c, setC] = useState(0) + + useEffect(() => { + setC(v => v + 1) + }, deps) + + useEffect(() => { + return effect() + }, [c]) +} + +export default useLazyEffect diff --git a/packages/react-vant/src/components/popover/Popover.tsx b/packages/react-vant/src/components/popover/Popover.tsx index a0f1c198f..d99f2a67c 100644 --- a/packages/react-vant/src/components/popover/Popover.tsx +++ b/packages/react-vant/src/components/popover/Popover.tsx @@ -4,15 +4,16 @@ import React, { useImperativeHandle, useRef, useState, -} from 'react'; -import cls from 'clsx'; -import { Instance, createPopper, offsetModifier } from '@vant/popperjs'; -import { PopoverAction, PopoverInstance, PopoverProps } from './PropsType'; -import { createNamespace, extend, pick } from '../utils'; -import { PopupInstanceType } from '../popup/PropsType'; -import { BORDER_BOTTOM } from '../utils/constant'; -import useClickAway from '../hooks/use-click-away'; -import Popup from '../popup'; +} from 'react' +import cls from 'clsx' +import { Instance, createPopper, offsetModifier } from '@vant/popperjs' +import { PopoverAction, PopoverInstance, PopoverProps } from './PropsType' +import { createNamespace, extend, pick } from '../utils' +import { PopupInstanceType } from '../popup/PropsType' +import { BORDER_BOTTOM } from '../utils/constant' +import useClickAway from '../hooks/use-click-away' +import Popup from '../popup' +import useLazyEffect from '../hooks/use-lazy-effect' const popupProps = [ 'overlay', @@ -26,17 +27,16 @@ const popupProps = [ 'onClosed', 'onOpened', 'onClickOverlay', -] as const; +] as const -const [bem] = createNamespace('popover'); +const [bem] = createNamespace('popover') const Popover = forwardRef( ({ children, className, ...props }, ref) => { - const [visible, updateShow] = useState(false); - - const popper = useRef(null); - const wrapperRef = useRef(); - const popoverRef = useRef(); + const [visible, updateShow] = useState(false) + const popper = useRef(null) + const wrapperRef = useRef() + const popoverRef = useRef() const createPopperInstance = () => createPopper(wrapperRef.current, popoverRef.current.popupRef.current, { @@ -55,53 +55,59 @@ const Popover = forwardRef( }, }), ], - }); + }) const updateLocation = () => { if (!visible) { - return; + return } if (!popper.current) { - popper.current = createPopperInstance(); + popper.current = createPopperInstance() } else { popper.current?.setOptions({ placement: props.placement, - }); + }) } - }; + } const onClickWrapper = () => { if (props.trigger === 'click') { - updateShow(!visible); + updateShow(!visible) } - }; + } const onClickAction = (action: PopoverAction, index: number) => { if (action.disabled) { - return; + return } - props.onSelect?.(action, index); + props.onSelect?.(action, index) if (props.closeOnClickAction) { - updateShow(false); + updateShow(false) } - }; + } const onClickAway = () => { - if (props.closeOnClickOutside && (!props.overlay || props.closeOnClickOverlay)) { - updateShow(false); + if ( + props.closeOnClickOutside && + (!props.overlay || props.closeOnClickOverlay) + ) { + updateShow(false) } - }; + } const renderAction = (action: PopoverAction, index: number) => { - const { icon, text, color, disabled, className: actionClassname } = action; + const { icon, text, color, disabled, className: actionClassname } = action return (
onClickAction(action, index)} > @@ -112,71 +118,75 @@ const Popover = forwardRef( : null}
{text}
- ); - }; + ) + } useEffect(() => { return () => { if (popper.current) { - popper.current?.destroy(); - popper.current = null; + popper.current?.destroy() + popper.current = null } - }; - }, []); + } + }, []) - useEffect(() => { - updateLocation(); - }, [visible, props.placement]); + useLazyEffect(() => { + updateLocation() + }, [visible, props.placement]) useEffect(() => { - let popupTarget; - const prevent = (e) => e.stopPropagation(); + let popupTarget + const prevent = e => e.stopPropagation() if (popoverRef.current && popoverRef.current.popupRef.current) { - popupTarget = popoverRef.current.popupRef.current; - popupTarget.addEventListener('touchstart', prevent); + popupTarget = popoverRef.current.popupRef.current + popupTarget.addEventListener('touchstart', prevent) } return () => { - if (popupTarget) popupTarget.removeEventListener('touchstart', prevent); - }; - }, [popoverRef.current]); + if (popupTarget) popupTarget.removeEventListener('touchstart', prevent) + } + }, [popoverRef.current]) useImperativeHandle(ref, () => ({ show: () => { if (visible) { - updateShow(false); - setTimeout(() => updateShow(true), 0); - return; + updateShow(false) + setTimeout(() => updateShow(true), 0) + return } - updateShow(true); + updateShow(true) }, hide: () => updateShow(false), - })); + })) - useClickAway(wrapperRef, onClickAway, 'touchstart'); + useClickAway(wrapperRef, onClickAway, 'touchstart') return ( <> - + {props.reference}
-
+
{children || props.actions.map(renderAction)}
- ); - }, -); + ) + } +) Popover.defaultProps = { overlay: false, @@ -189,6 +199,6 @@ Popover.defaultProps = { trigger: 'click', actions: [], placement: 'bottom', -}; +} -export default Popover; +export default Popover