type="nal"

리액트 블로그-3. 좋아요 버튼(setState) 본문

Web Development/React

리액트 블로그-3. 좋아요 버튼(setState)

nalmi 2025. 1. 3. 17:05

안 쓰는 변수들이 있을 경우 이렇게 경고 메세지가 뜨는데, 이걸 무시할 수도 있지만

제일 상단에 /*eslint-disable*/ 해당 코드를 적어주면 경고가 다 무시된다.

 

글 제목 옆에 좋아요 버튼을 만들어줄건데

button 태그로 만들면 너무 안예쁨.

span태그로 만들어준다.

이때 숫자가 변하는 좋아요 갯수는 state로 만들어준다. 

state를 변경하는 함수명은 setLikes로 지었는데, 보통 set접두어를 붙이는 것이 관례이다.

그리고 span 태그에 onClick 이벤트핸들러를 적어준다.

onClick 안에는 실행할 함수를 외부에 적거나 화살표 함수로 적어줌

 

위처럼 기존 state에 + 1을 해주면 숫자가 잘 증가하지만, 게시글들이 모두 같은 변수를 공유하게 된다.

현재 글 3개만 임시로 관리하고 있기 때문에 likes도 배열로 만들어줘서 map의 이미 사용하고 있는 인덱스를 이용하도록 했고,

increaseLike()함수를 따로 빼주었다.

뭔가 함수를 아래처럼 만들면 될 것 같지만..

  const increaseLike = (i) => {
    setLikes(likes[i] + 1);
  }

setLikes는 상태 전체를 한 번에 업데이트하는 함수로, 배열의 개별 요소만 따로 업데이트할 수 없다.

그래서 배열을 새로 복사하고 업데이트 한 후, setLikes()로 전체 배열에 적용하도록 했다.

 

  const increaseLike = (i) => {
    const newLikes = [...likes];
    newLikes[i]++;
    setLikes(newLikes);
  }

 

여기서 [...likes]는 구조분해 할당(spread operator 스프레드 연산자)인데,

 

1. [...likes] likes 배열의 모든 요소를 풀어서 배열에 복사

const newLikes = [...likes];

코드는 이렇게 동작함

const newLikes = [0, 0, 0];  // 완전히 새로운 배열이 생성됨

 

2. 이렇게 하지 않고 직접 할당하면

const newLikes = likes;  // 참조만 복사되어 같은 배열을 가리킴

=> state의 동작원리에서

기존 state와 신규state를 비교해서 같으면 변경하지 않기 때문에 수정사항이 반영되지 않는다.

 

3. 다른 방법으로는

const newLikes = likes.slice();  // 이것도 배열 생성

const newLikes = Array.from(likes);  // 이것도 가능

 

spread operator(...)를 사용하는 이유는?

  1. 원본 배열을 변경하지 않고 복사본 생성
  2. 얕은 복사(shallow copy) 쉽게 만들 있음
  3. 코드가 간결하고 읽기 쉬움

좋아요가 각각 반영됨

 

현재 코드는 이렇다

/*eslint-disable*/
import './App.css';
import { useState } from 'react';

function App() {

  let post = '대전 찐 맛집';
  let [titles, b] = useState(['충남대 디저트 맛집', '회식 장소 추천', '리액트 공부']);
  let [dates, d] = useState(['1월 2일', '1월 3일', '1월 3일']);
  let [likes, setLikes] = useState([0, 0, 0]);

  const increaseLike = (i) => {
    const newLikes = [...likes];
    newLikes[i]++;
    setLikes(newLikes);
  }

  return (
    <div className="App">
      <div className="black-nav">
        <h4 style={{ color: 'pink', 'fontSize': '16px' }}>nalmi's blog</h4>
      </div>
      {titles.map((title, i) => (
        <div className='list' key={i}>
          <h4>{title} <span onClick={() => {increaseLike(i)}}>🩵</span> { likes[i] } </h4>
          <p>{dates[i]} 발행</p>
        </div>
      ))}
    </div>
  );
}

export default App;

 

 

https://youtu.be/GOiCobCh2Ig?si=wzwx77ww6ONrcVKi