Closed un0211 closed 2 months ago
๊ทธ๊ฒ๋ ๋ฐ๋ก ์์ ํด์ ๋จธ์งํ ๊ฒ์~~
์ ๊ฐ ์ธ๋ถ ํด๋ฆญ์์๋ ๋๋กญ๋ค์ด ๋ซํ๊ฒ ํ๋ ค๊ณ ์๋ํด๋ดค๋๋ฐ, ์ ์ ๋๋ค์..ใ 9d6567e ์ปค๋ฐ ๋ณด์๊ณ ํน์ ์ด์ ๋ฅผ ์ ๊ฒ ๊ฐ์ ๋ถ ์์ผ๋ฉด ๋์์์ฒญ ๋๋ฆฝ๋๋ค!!
๋์๋์ด auth redirection ํ์ จ๋ ๊ฒ์์ ์์ด๋์ด๋ฅผ ์ป์ด ๊ด๋ฆฌํด์ค ํจ์๋ฅผ ๋ง๋ค์ด๋ดค์ต๋๋ค! isOpen์ ๊ฐ๋ง ๋ณต์ฌ๋์ด์ ๋ณํ๊ฐ ์๋๋ ๊ฑด ์๋๊น ํ๊ณ getIsOpen = () => isOpen๋ ํด๋ณด๊ณ , ๊ฐ์ฒด๋ก๋ ๋ฐ๊ฟ๋ดค๋๋ฐ ์ ์๋๋ค์ ใ (ํฌ์ธํฐ ๋๊ฒจ์ฃผ๊ณ ์ถ์ ์ฌ์ ..) UserMenuDropdown ๋ด์์๋ ์ ๋์ํ๋๋ฐ ๋ฐ์์ setIsOpen(false)๋ก ํด๋ ๋ซํ์ง ์์ต๋๋ค.. (useRef๋ ์๋ํ์ง ์์๋๋ฐ, onClick ์์ฒด๊ฐ ์๋จนํ๋ ๊ฑด ์๋๊ณ (์ฝ์ ๋ก๊ทธ ์ฐ์ผ๋ฉด ์ฐํ), setIsOpen์ด ์ ์๋๋ ๊ฒ ๊ฐ์์์ ๋๋ค!)
๋ค๋ฅธ ๊ด์ฐฎ์ ๋ฐฉ๋ฒ ์์ผ์๋ฉด 9d6567e ๋ ๋ ค๋ฒ๋ฆฌ๊ณ force push ํ์ ๋ ๋ฉ๋๋ค!! Context๋ redux ์ฐ๋ ๊ฒ ๋์ผ๋ ค๋์...
๋ฉํ ๋์ด ๋ง์ํด์ฃผ์ ๊ฒ ์ฒ๋ผ ref ์ฌ์ฉํด์ ์์ ํ๋๊น ์ ์๋ํฉ๋๋ค ๐ซก๐
import Link from 'next/link';
import UserProfile from './UserProfile';
import useUserDropdown from '@/hooks/useUserDropdown';
export default function UserMenuDropdown() {
const { status, handleDropdownClick, handleMenuClick, handleLogoutClick, dropdownRef } = useUserDropdown();
return (
<div className='flex items-center' ref={dropdownRef}>
<button type='button' onClick={handleDropdownClick}>
<UserProfile />
</button>
{status.isOpen && (
<ul className='dd-container absolute right-2 top-14 w-28 bg-white text-sm md:top-16 md:w-[150px] md:text-base'>
<li className='dd-menu md:h-10' onClick={handleMenuClick}>
<Link href='/mydashboard' className='align-center size-full'>
๋ด ๋์๋ณด๋
</Link>
</li>
<li className='dd-menu md:h-10' onClick={handleMenuClick}>
<Link href='/mypage' className='align-center size-full'>
๊ณ์ ๊ด๋ฆฌ
</Link>
</li>
<li className='dd-menu md:h-10'>
<button type='button' className='align-center size-full' onClick={handleLogoutClick}>
๋ก๊ทธ์์
</button>
</li>
</ul>
)}
</div>
);
}
import { useRouter } from 'next/router';
import { MouseEventHandler, useState, useEffect, useRef } from 'react';
import { useDispatch } from 'react-redux';
import { clearUser } from '@/store/reducers/userSlice';
const useUserDropdown = () => {
const router = useRouter();
const dispatch = useDispatch();
const [status, setStatus] = useState({ isOpen: false });
const dropdownRef = useRef<HTMLDivElement | null>(null);
const handleOutsideClick = (event: MouseEvent) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
setStatus({ isOpen: false });
}
};
useEffect(() => {
if (status.isOpen) {
document.addEventListener('mousedown', handleOutsideClick);
} else {
document.removeEventListener('mousedown', handleOutsideClick);
}
return () => {
document.removeEventListener('mousedown', handleOutsideClick);
};
}, [status.isOpen]);
const handleDropdownClick: MouseEventHandler<HTMLButtonElement> = (e) => {
e.stopPropagation();
setStatus((prev) => ({ isOpen: !prev.isOpen }));
};
const handleMenuClick: MouseEventHandler<HTMLLIElement> = (e) => {
e.stopPropagation();
setStatus({ isOpen: false });
};
const handleLogoutClick: MouseEventHandler<HTMLButtonElement> = (e) => {
e.stopPropagation();
dispatch(clearUser());
setStatus({ isOpen: false });
router.push('/');
};
return {
status,
handleDropdownClick,
handleMenuClick,
handleLogoutClick,
dropdownRef,
};
};
export default useUserDropdown;
ref ์์ด ๊ทธ๋ฅ useEffect๋ก ์ ์ญ์ ์ด๋ฒคํธ ๋ฃ์ด์ฃผ๋ฉด ํด๊ฒฐ์ด ๋๋ค์
import { useRouter } from 'next/router';
import { MouseEventHandler, useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import { clearUser } from '@/store/reducers/userSlice';
const useUserDropdown = () => {
const router = useRouter();
const dispatch = useDispatch();
const [status, setStatus] = useState({ isOpen: false });
const handleOutsideClick = () => {
console.log(status.isOpen);
setStatus({ isOpen: false });
};
useEffect(() => {
if (status.isOpen) {
document.addEventListener('mousedown', handleOutsideClick);
} else {
document.removeEventListener('mousedown', handleOutsideClick);
}
return () => {
document.removeEventListener('mousedown', handleOutsideClick);
};
}, [status.isOpen]);
const handleDropdownClick: MouseEventHandler<HTMLButtonElement> = (e) => {
e.stopPropagation();
setStatus((prev) => ({ isOpen: !prev.isOpen }));
};
const handleMenuClick: MouseEventHandler<HTMLLIElement> = (e) => {
e.stopPropagation();
setStatus({ isOpen: false });
};
const handleLogoutClick: MouseEventHandler<HTMLButtonElement> = (e) => {
e.stopPropagation();
dispatch(clearUser());
setStatus({ isOpen: false });
router.push('/');
};
return { status, handleOutsideClick, handleDropdownClick, handleMenuClick, handleLogoutClick };
};
export default useUserDropdown;
์ค...!! ์ด๋ฐ ๊ฑธ ์ด์ ์ผ ๋ดค๋ค์!! ํ์ธํด๋ณด๊ณ ๋ฐ์ํ๊ฒ ์ต๋๋ค!
addEventListener ํ๋๊น ๋๋กญ๋ค์ด์ด ๋์์ ์ํ๋ค์ใ ๋ชจ๋ ๋๋กญ๋ค์ด์ ๋๊ธฐ๋ง ํด์ใ ์ฒซ๋ฒ์งธ์ฒ๋ผ useRef ์จ์ผ ํ๋ ค๋ ๋ด์
๋ฏผ์ฌ๋ ์๋ ค์ฃผ์ ์ฝ๋๋ก dropdown ์ ์ญ์์ ๋ซํ๋๋ก ์ค์ ํ์ต๋๋ค!! ์ ๊ฐ ์ค์๋ก .env๋ฅผ ์ฌ๋ ค๋ฒ๋ ค์ ์๋ ๋ฒ์ ์ผ๋ก force push ํด๋ฒ๋ ธ์ด์...ใ ใ ใ
์์ ํฌ๊ธฐ์์ absolute ๋๋ฌธ์ ์์น ์ด์ํ๊ฒ ๋ ๊ฑฐ ๊ณ ์น๋ค๋ ๊ฒ ๋ค๋ฅธ ์๊ธฐํ๋ค๊ฐ ๊น๋นกํ๋ค์......! ์ด๋ฏธ ๋ซ์๋ฒ๋ ธ์ผ๋ ๋์์ธ ์์ ์ฌํญ์ ์ถ๊ฐํ ๊ฒ์
์ฐ๊ด๋ ์ด์
์์ ๋ด์ฉ
์คํฌ๋ฆฐ์ท
https://github.com/Part3-Team15/taskify/assets/24778465/63d6913f-d075-4ae3-9e63-cd88e4b402db