React.js

react에서 useHover 커스텀훅과 hover시 modal 재사용 컴포넌트

Dev갱이 2024. 10. 9. 11:48
728x90
// GroupAndMemberProfile.tsx
...

const { handleMouseOver, handleMouseOut, isHovering } = useHover();

...

return (
	...
    <div className={styles.group_profile_container}>
        <div
            className={styles.group_image_container}
            onMouseOver={e => {
                handleMouseOver(0);
            }}
            onMouseOut={e => {
                handleMouseOut();
            }}
        >
            <Image
                fill
                src={
                    groupCoverImage
                        ? groupCoverImage
                        : '/images/banner/sm/group-base-sm.png'
                }
                alt="group-img"
            />
            {isHovering === 0 && (
                <AnimatePresence key={0}>
                    <motion.div
                        key={0}
                        className={styles.group_hover_modal}
                        initial={{ opacity: 0 }}
                        animate={{ opacity: 1, y: 0, transition: { duration: 0.5 } }}
                        exit={{ opacity: 0, transition: { duration: 1 } }}
                    >
                        <GroupHoverModal sharedGroup={group} />
                    </motion.div>
                </AnimatePresence>
            )}
        </div>
        <div
            className={styles.profile_container}
            onMouseOver={e => {
                handleMouseOver(1);
            }}
            onMouseOut={e => {
                handleMouseOut();
            }}
        >
            <Image
                className="rounded-full"
                fill
                src={member.profileImage ?? '/images/profile/profile.png'}
                alt="profile-img"
            ></Image>

            {isHovering === 1 && (
                <AnimatePresence key={1}>
                    <motion.div
                        key={1}
                        className={styles.mention_view_modal}
                        initial={{ opacity: 0 }}
                        animate={{
                            opacity: 1,
                            y: 0,
                            transition: { duration: 0.5 },
                        }}
                        exit={{ opacity: 0, transition: { duration: 1 } }}
                    >
                        <MemberHoverModal
                            mentionRecipient={member}
                        ></MemberHoverModal>
                    </motion.div>
                </AnimatePresence>
            )}
        </div>
    </div>
    ...
);

 

// SharedMembers.tsx
...

const { handleMouseOver, handleMouseOut, isHovering } = useHover();

...

return (
	...
    
    <div className={styles.shared_members_img_container}>
        <div
            className={styles.group_image_container}
            onMouseOver={e => {
                handleMouseOver(0);
            }}
            onMouseOut={e => {
                handleMouseOut();
            }}
        >
            <Image
                fill
                src={
                    groupCoverImage
                        ? groupCoverImage
                        : '/images/banner/sm/group-base-sm.png'
                }
                alt="group-img"
            />
            {isHovering === 0 && (
                <AnimatePresence key={0}>
                    <motion.div
                        key={0}
                        className={styles.group_hover_modal}
                        initial={{ opacity: 0 }}
                        animate={{ opacity: 1, y: 0, transition: { duration: 0.5 } }}
                        exit={{ opacity: 0, transition: { duration: 1 } }}
                    >
                        <GroupHoverModal sharedGroup={sharedGroup} />
                    </motion.div>
                </AnimatePresence>
            )}
        </div>
        <div
            className={styles.img_conatiner}
            onMouseOver={e => {
                handleMouseOver(1);
            }}
            onMouseOut={e => {
                handleMouseOut();
            }}
        >
            <Image
                className={styles.profile_img}
                fill
                src={
                    sharedMembers[0].member.profileImage ??
                    '/images/profile/profile.png'
                }
                alt="profile-img"
            ></Image>

            {isHovering === 1 && (
                <AnimatePresence key={1}>
                    <motion.div
                        key={1}
                        className={styles.mention_view_modal}
                        initial={{ opacity: 0 }}
                        animate={{ opacity: 1, y: 0, transition: { duration: 0.5 } }}
                        exit={{ opacity: 0, transition: { duration: 1 } }}
                    >
                        <MemberHoverModal
                            mentionRecipient={sharedMembers[0].member}
                        ></MemberHoverModal>
                    </motion.div>
                </AnimatePresence>
            )}
        </div>
    </div>
    ...
    
);

 

두 코드는 Group Profile과 Member Profile을 hover 했을때 각각 해당 정보를 보여주는 modal을 보여주었다가 hover가 mouse out되었을때 다시 숨겨지는 코드이다.
근데 해당 코드는 여기에서만 사용되는것이 아니라 hover되는 거의 모든곳에 사용되고 중복 코드가 발생하기 때문에 컴포넌트화 해주는것이 좋을것 같다. 고려 해야 될 케이스는 다음과 같다.
  1. group_profile_container안에 GroupHoverModal과 MemberHoverModal 둘다 있는 경우
  2. GroupHoverModal만 있는 경우
  3. MemberHoverModal만 있는 경우

useHover.ts

import { useState } from 'react';

export const useHover = () => {
	const [isHovering, setIsHovering] = useState<number | null>(null);

	const handleMouseOver = (index: number) => {
		setIsHovering(index);
	};

	const handleMouseOut = () => {
		setIsHovering(null);
	};

	return {
		handleMouseOver,
		handleMouseOut,
		isHovering,
	};
};

 

ProfileHoverContainerModal

 

 

useHover 커스텀 훅을 ProfileHoverContainerModal을 호출하는 곳에서 선언하여 추가적으로 발생하는 Hover modal을 유동적으로 추가할 수 있게 구성 했다.

 

 

GroupHoverModal과 MemberHoverModal 둘다 있는 경우

 

MemberHoverModal만 있는 경우

 

classNames를 사용하여 member_profile만 존재 하는 경우에는 container의 border를 없애고 profile 이미지만 보이게 하였다. 이런식으로 조건도 유동적으로 줄 수 있게 된다.

 

추가적인 hover-modal이 존재 할때

 

useHover 커스텀훅과 ProfileHoverContainerModal을 사용하여 기존 Group-hover-modal과 profile-hover-modal을 사용하고 추가 적인 SharedMembersHoverModal이 추가 되었을때 이런식으로 호출하는 부분에서 useHover를 선언해서 확장성 있게 추가할 수 있다.
728x90