Content.jsx - 각 컨텐츠 별 좋아요 기능 관리

박소현·2025년 4월 14일

Circle

목록 보기
17/19


우선 내가 만들 기능은 하트 버튼 클릭 시 좋아요가 눌리는 기능이다.
전체적인 구성을 보면 일단 구조가 같은 형태의 UI가 반복이 되고 있기 때문에 이 역시 map 메서드를 통해 코드를 간략화하였다.

 const populars = [
        { title : "0", intro : "", number : "" },
        { title : "1", intro : "", number : "" },
        { title : "2", intro : "", number : "" },
        { title : "3", intro : "", number : "" },
        { title : "4", intro : "", number : "" },
        { title : "5", intro : "", number : "" },
        { title : "6", intro : "", number : "" },
        { title : "7", intro : "", number : "" },
    ]
    
     <div className='main_circle_cont'>
           { populars.map((popular, index) => (
           <div className='main_row_01'
           key={index}>
               <h4>{popular.title}</h4>
               <p className='circle_intro'>{popular.intro}</p>
               <p className='people_num'><img src= {peopleIcon} alt="인원수" />{popular.number}</p>
               <button className='like_circle'>
       				<img src={} alt="찜하기"/>
               </button>
   		  </div>
    		))}
	</div>
    

위와 같이 작성하면 코드가 훨씬 간결해지고 유지보수도 용이해진다.
그리고 버튼 안에 onClick 으로 해당 써클 클릭 시 하트가 눌리는 기능을 구현했다.

import unLikeIcon from '../images/favorite_stroke_black_icon.svg'
import likeIcon from '../images/favorite_black_icon.svg'

 const [ likedPopular, setLikedPopular ] = useState(unLikeIcon);
 
  const handleFavorite = (circle) => {
        setLikedPopular(isLike === unLikeIcon ? likeIcon : unLikeIcon);
    }
 
 <div className='main_circle_cont'>
           { populars.map((popular, index) => (
           <div className='main_row_01'
           key={index}>
               <h4>{popular.title}</h4>
               <p className='circle_intro'>{popular.intro}</p>
               <p className='people_num'><img src= {peopleIcon} alt="인원수" />{popular.number}</p>
               <button className='like_circle'>
       				<img src={likedPopular} alt="찜하기"
                    onClick={()=>{handleFavorite(circle)}}/>
               </button>
   		  </div>
    		))}
</div>
 
 

문제점 : 이렇게 코드를 구성하면 각각의 컴포넌트가 아니라 전체 컴포넌트가 동시에 관리되기 때문에 하나의 ui에 좋아요를 누르면 모든 컴포넌트에 반영된다.

기능별로 좋아요 설정 관리하기

주요 키워드

  • spread operator(전개 연산자) ...prev
  • 객체 상태에서 특정 key만 동적으로 업데이트 [param]: !prev[param]
  • 객체에서 키 접근하는 방식 알기 [ ]

1. useState 안에 배열 {}넣기

const [likedPopular, setLikedPopular] = useState({});

< 객체 안의 상태 >

  • circle의 title을 key로 해서 좋아요 여부를 true/false로 저장
{
  "enhypen": true,  // 좋아요 누름
  "bts": false,     // 좋아요 안 누름
}

2. 좋아요 버튼 클릭 시 실행될 함수

const handleFavorite = (circleTitle) => {
    setLikedCircles(prev => ({
        ...prev,
        [circleTitle]: !prev[circleTitle] 
    }));
};

이전 상태 prev

prev = {
  "enhypen": true,
  "bts": false
}

결과

{
  "enhypen": true,
  "bts": true  // ← 값만 바뀐 거!
}

리액트에서 상태 업데이트 하는 방식 ...전개 연산자

⭐⭐ ...prev는 전개 연산자로 기존 데이터를 유지한 채, 특정 항목만 덮어쓰기(업데이트)하는데 사용됨 , 리액트에서 상태를 안전하게 업데이트할 때 아주 자주 쓰이는 패턴이기 때문에 알아둘것!

기존 토글 방식과 객체 토글 방식 비교

setIs(!is) // 단일 패턴 토글 시 사용

[circleTitle]: !prev[circleTitle] // 여러 개의 패턴 토글 시 사용 
⭐⭐ 객체 상태에서 특정 key만 동적으로 업데이트할 때 사용 

3. 객체에서 변수를 키로 접근하기 - [ ]

{circles.map((circle, index) => (
    <div className='main_row_01' key={index}>
        <div>
            <h4>{circle.title}</h4>
            <p className='circle_intro'>{circle.intro}</p>
            <p className='people_num'><img src={peopleIcon} alt="인원수" />{circle.number}</p>
            <button className='like_circle' onClick={() => handleFavorite(circle.title)}> // 타이틀명을 기준으로 true / false를 구분하기 때문에 인자로 전달
                <img 
                    src={likedCircles[circle.title] ? likeIcon : unLikeIcon} 
                    // 객체에서 변수를 키로 접근할 때 []대괄호 사용
                    alt="찜하기" 
                />
            </button>
        </div>
    </div>
))}

0개의 댓글