Framework/React

[React] λ¦¬μ•‘νŠΈ 툴팁 (Tooltip) κ΅¬ν˜„ν•˜κΈ° / μ™ΈλΆ€μ˜μ—­ 클릭 μ‹œ 툴팁 μˆ¨κΈ°λŠ” 방법

yuri lee 2023. 3. 21. 23:51
λ°˜μ‘ν˜•

Intro

μ•ˆλ…•ν•˜μ„Έμš”. μ΄λ²ˆμ‹œκ°„μ—λŠ” λ¦¬μ•‘νŠΈμ—μ„œ νˆ΄νŒμ„ κ΅¬ν˜„ν•˜λŠ” 방법, 툴팁 μ™ΈλΆ€ μ˜μ—­ 클릭 μ‹œ νˆ΄νŒμ„ μˆ¨κΈ°λŠ” 방법에 λŒ€ν•΄ μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€. 

 

 

Let's look at detail

μ•„λž˜μ™€ 같은 λΆ€λͺ¨ μ»΄ν¬λ„ŒνŠΈκ°€ μžˆλ‹€κ³  κ°€μ •ν•΄λ΄…μ‹œλ‹€. 3개의 툴팁 μ»΄ν¬λ„ŒνŠΈκ°€ 있고, 툴팁 μ»΄ν¬λ„ŒνŠΈμ—λŠ” 각기 λ‹€λ₯Έ 툴팁 μ„€λͺ…을 props둜 μ „λ‹¬ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 

const SomeComponent: NextPage<Props> = props => {
  return (
       <article>
            <dl>
                <dt>
                    λ‰΄μŠ€
                    <Tooltip desc={'λ‰΄μŠ€ κ΄€λ ¨ νˆ΄νŒμž…λ‹ˆλ‹€.'} />
                </dt>
                <dt>
                    μ‡Όν•‘
                    <Tooltip desc={'μ‡Όν•‘ κ΄€λ ¨ νˆ΄νŒμž…λ‹ˆλ‹€.'} />
                </dt>
                <dt>
                    지도
                    <Tooltip desc={'지도 κ΄€λ ¨ νˆ΄νŒμž…λ‹ˆλ‹€. '} />
                </dt>
            </dl>
        </article>
  );
}

export default SomeComponent;

 

툴팁 μ»΄ν¬λ„ŒνŠΈλŠ” μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ ν˜„μž¬ κ΅¬ν˜„λ˜μ–΄ μžˆλŠ” 툴팁 μ»΄ν¬λ„ŒνŠΈλŠ” λ¬Έμ œκ°€ μžˆμ—ˆμŠ΅λ‹ˆλ‹€, μ„ νƒλœ 툴팁이 μžˆμ„ λ•Œ λ‹€λ₯Έ 툴팁이 μ„ νƒλ˜μ–΄λ„, λ™μ‹œμ— 툴팁 descκ°€ ν‘œμΆœλ©λ‹ˆλ‹€. λ˜ν•œ μ™ΈλΆ€ μ˜μ—­μ„ 클릭 ν• λ•Œ μ—¬μ „νžˆ 툴팁이 남아 μžˆμ—ˆμŠ΅λ‹ˆλ‹€. 

const Tooltip: NextPage<Props> = props => {
    const [tooltip, setTooltip] = useState(false),
        tooltipRef: any = useRef<HTMLDivElement>(null),
        [offsetTop, setOffsetTop] = useState(0);

    useEffect(() => {
        const tooltipOffsetTop = tooltipRef?.current?.offsetTop + 30;
        setOffsetTop(tooltipOffsetTop);
    }, []);

    return (
        <span className={styles.tooltip} ref={tooltipRef}>
            <button type="button" className={tooltip ? styles.active : ''} onClick={() => setTooltip(!tooltip)}>
                βœ”οΈ
            </button>
            {tooltip && (
                <div style={{top: offsetTop}} onClick={() => setTooltip(false)}>
                    {props.desc}
                </div>
            )}
        </span>
    );
};

export default Tooltip;

 

 

How to solve the problem

ν•΄λ‹Ή 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ μ €λŠ” handleOutsideClick μ΄λΌλŠ” ν•¨μˆ˜λ₯Ό λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€. 이 ν•¨μˆ˜λŠ” mousedown 이벀트λ₯Ό μˆ˜μ‹ ν•˜κ³ , μ„ νƒλœ 툴팁 μ˜μ—­ μ™ΈλΆ€λ₯Ό 클릭할 λ•Œ μ„ νƒλœ νˆ΄νŒμ„ ν•΄μ œν•˜λŠ” 역할을 ν•©λ‹ˆλ‹€. 

 

λ˜ν•œ useEffect hooksλ₯Ό μ‚¬μš©ν•˜μ—¬ μ»΄ν¬λ„ŒνŠΈκ°€ mountλ˜κ±°λ‚˜, tooltipRef값이 변경될 λ•Œλ§ˆλ‹€ on / off κ°€ λ©λ‹ˆλ‹€. λ”°λΌμ„œ ν•΄λ‹Ή μ½”λ“œλ₯Ό 톡해 μ„ νƒλœ 툴팁이 μžˆμ„ λ•Œ λ‹€λ₯Έ νˆ΄νŒμ„ 선택 μ‹œ μ„ νƒλœ 툴팁으둜 ν•΄μ œλ˜λŠ” 효과λ₯Ό 얻을 수 μžˆμŠ΅λ‹ˆλ‹€. 

const Tooltip: NextPage<Props> = props => {
    const [tooltip, setTooltip] = useState(false),
        tooltipRef: any = useRef<HTMLDivElement>(null),
        [offsetTop, setOffsetTop] = useState(0);

    const toggleTooltip = () => {
        setTooltip(!tooltip);
    };

    useEffect(() => {
        const tooltipOffsetTop = tooltipRef?.current?.offsetTop + 30;
        setOffsetTop(tooltipOffsetTop);
    }, []);

    useEffect(() => {
        const handleOutsideClick = (event: MouseEvent) => {
            if (tooltipRef.current && !tooltipRef.current.contains(event.target as Node)) {
                setTooltip(false);
            }
        };

        document.addEventListener('mousedown', handleOutsideClick);
        return () => {
            document.removeEventListener('mousedown', handleOutsideClick);
        };
    }, [tooltipRef]);

    return (
        <span className={styles.tooltip} ref={tooltipRef}>
            <button type="button" className={tooltip ? styles.active : ''} onClick={toggleTooltip}>
                βœ”οΈ
            </button>
            {tooltip && (
                <div style={{top: offsetTop}}>
                    {props.description}
                </div>
            )}
        </span>
    );
};

export default Tooltip;

 


https://developer.mozilla.org/en-US/docs/Web/API/Element/mousedown_event

 

 

λ°˜μ‘ν˜•