state 변경

이윤희·2024년 12월 16일

React/Next 일기

목록 보기
2/52

react 숙제를 하는데 아무리 생각해도 모르겠어서 정말 많은 시도를 해봤다

      /* map으로 각각 따봉이 반영되는거... 어떻게 하나 실험해봄. =========
      1. a.따봉 이렇게할까? > 안됨. NaN 뜸
      2. let [따봉, 따봉변경] = useState([0, 0, 0]); < 이렇게 state안에 [0,0,0]으로했더니 왜인지모르겠지만
      초기값 000 -> 누르면 0,0,011111111 <이렇게 됨... 뭐지?
      3. a.따봉변경(따봉 + 1); < 안됨. 오류
      4. 따봉변경(따봉[i] + 1); < NaN
      5. 따봉0 따봉1 따봉2 따봉변경0 따봉변경1 따봉변경2 이렇게 만들어서 변수자리에 ㅋㅋㅋ 따봉i 라고 써봤는데 오류뜸...
      6. 진짜 혹시나 해서 e 랑 e.target.따봉변경 이렇게 해봤는데 오류 ㅠㅠ
      7. 따봉변경[i](따봉 + 1); < 오류 */

설명을 봤는데도 음,........................ 싶어서 chatGPT한테 물어봤다.



난 간단한 게시판을 만들고 있고, map 함수를 이용해 html을 반복적으로 출력했다.
그리고 각각의 게시글에는 '좋아요' 버튼인 '따봉'이 있다.

내가 기존에 짰던 코드 :


let [따봉, 따봉변경] = useState(0);

(중간 생략)
return( 
(중간 생략)
글제목.map((a, i) => {
          return (
            <div className="list">
              <h4
                onClick={() => {
                  setModal(true);
                  modal == true ? setModal(false) : ""; }}
              >
                {a}
                <span
                  onClick={() => { 따봉변경(따봉+1) }}
                >
                  {" "}
                  🥰
                </span>{" "}
                {따봉}{" "} 
              </h4>
              <p>126일 발행</p>
            </div>
          );
        }))

내가 정답을 보고 새로 작성한 코드 :

<div className="list">
              <h4
                onClick={() => {
                  setModal(true);
                  modal == true ? setModal(false) : "";
                }}
              >
                {a}
                <span
                  onClick={() => {
                    // 0번째 좋아요 버튼을 클릭시엔 따봉[0] + 1 을 해야하고
                    // 1번째 좋아요 버튼을 클릭시엔 따봉[1] + 1 을 해야하고
                    // 2번째 좋아요 버튼을 클릭시엔 따봉[2] + 1 을 해야함

                    let copy = [...따봉]; // 우선 카피본을 만들어주고
                    copy[i] = copy[i] + 1; //copy[i]번째 숫자에 copy[i] + 1을 대입
                    따봉변경(copy); // 따봉 state를 copy본으로 갈아치운다.
                  }}
                >
                  {" "}
                  🥰
                </span>{" "}
                {따봉[i]}{" "}
                {/* 여기서 내가 {따봉}을 써서 000이 다나온거였음!!!! 여기서도 i번째 인덱스를 썼어야 했음. */}
              </h4>
              <p>126일 발행</p>
            </div>
          );
        })"

이전 코드에서 따봉변경(따봉+1)을 하는 건 이해가 됐는데,
이후 코드에서 copy[i] = copy[i]+1을 하면 이것과 동일한 결과가 나오는 게 왜 그런지 궁금해서 물어봤다.

웃긴거 : GPT가 질문 칭찬해줌ㅋㅋㅋㅋㅋㅋ



GPT

좋아요! 질문이 아주 훌륭합니다. 기존 코드와 수정한 코드에서 동작 원리를 이해하려면, React의 state 업데이트 방식값의 참조와 복사에 대해 이해해야 합니다. 아래에서 하나씩 차근차근 설명할게요.


1. 이전 코드에서 따봉변경(따봉 + 1)이 어떻게 동작했는가?

<span onClick={() => { 따봉변경(따봉 + 1) }}>
  🥰
</span> {따봉}
  • 이전 코드는 좋아요 카운트가 단일 값(따봉)일 때 작동하는 방식입니다.
  • 따봉은 단순히 숫자(0, 1, 2, ...)이고, 따봉변경은 이를 업데이트하는 함수입니다.
  • 따봉 + 1따봉 값을 1 증가시켜서, 새로운 값으로 업데이트합니다.
  • 이 방식에서는 모든 게시글에 대해 동일한 따봉 상태를 공유하므로, 어떤 게시글의 "좋아요"를 눌러도 모든 게시글이 동일한 따봉 값을 표시하게 됩니다.

2. 수정된 코드에서 따봉을 배열로 사용한 이유

문제는, 게시글별로 독립적인 따봉 값을 저장하고 싶다는 점입니다. 이를 해결하기 위해, 따봉배열로 만들어 각 게시글마다 별도의 좋아요 카운트를 관리할 수 있도록 했습니다.

let [따봉, 따봉변경] = useState([0, 0, 0]); // 게시글마다 좋아요 수를 저장

위 코드에서 따봉은 배열입니다. 예를 들어, [0, 0, 0]이라면:

  • 따봉[0]: 첫 번째 게시글의 좋아요 수.
  • 따봉[1]: 두 번째 게시글의 좋아요 수.
  • 따봉[2]: 세 번째 게시글의 좋아요 수.

3. 왜 배열의 복사가 필요한가?

React에서는 state를 직접 변경하면 안 됩니다. 예를 들어, 아래처럼 작성하면 오류를 유발할 수 있습니다:

따봉[i] = 따봉[i] + 1; // 직접적으로 state를 변경
따봉변경(따봉);        // state 업데이트

이유:

React의 state는 변경이 감지될 때만 컴포넌트를 다시 렌더링합니다. 만약 state를 직접 변경하면 React는 "state가 변경되었는지"를 알 수 없어서 다시 렌더링이 발생하지 않을 수도 있습니다. 이는 React가 상태 변경을 감지하기 위해 === 비교를 수행하기 때문입니다.


4. let copy = [...따봉]이란?

let copy = [...따봉]따봉 배열의 복사본을 만드는 코드입니다.

  • [...따봉]spread 문법으로, 기존 배열의 값을 새 배열로 복사합니다.
  • 이렇게 하면 기존 배열(따봉)은 그대로 유지되고, 복사본(copy)에서 작업을 수행할 수 있습니다.

5. 수정된 코드가 어떻게 동작하는가?

let copy = [...따봉];    // 따봉 배열 복사
copy[i] = copy[i] + 1;   // i번째 게시글의 좋아요 수 증가
따봉변경(copy);          // 복사본을 새로운 state로 설정
  • copy를 만들고, copy[i]의 값을 수정합니다.
  • 수정된 배열 copy따봉변경을 통해 React state로 업데이트합니다.
  • 이 과정에서 React는 새로운 배열(copy)을 이전 상태와 비교(===)하여 "state가 변경되었다"는 것을 감지하고, 컴포넌트를 다시 렌더링합니다.
  • 이 방식으로, 각 게시글의 좋아요 수를 독립적으로 관리할 수 있게 됩니다.

6. 따봉[i] = 따봉[i] + 1copy[i] = copy[i] + 1의 차이점

(1) 따봉[i] = 따봉[i] + 1 (잘못된 방식)

  • 직접적으로 state인 따봉을 수정하는 방식입니다.
  • React는 이 변화를 감지하지 못하므로 컴포넌트를 다시 렌더링하지 않습니다.
  • 따라서 버튼을 클릭해도 화면에 변화가 나타나지 않을 수 있습니다.

(2) let copy = [...따봉]; copy[i] = copy[i] + 1; (올바른 방식)

  • 새로운 배열(copy)을 생성하여, 복사본의 값을 변경합니다.
  • 복사본을 새로운 state로 설정하면 React는 "state가 변경되었다"고 판단하고 컴포넌트를 다시 렌더링합니다.

7. React의 state 관리 원칙

React에서 state를 변경할 때는 항상 불변성(immutability)을 유지해야 합니다.

  • 즉, 기존의 state를 직접 수정하지 않고, 복사본을 만들어 새로운 상태로 설정해야 합니다.
  • 이는 React가 효율적으로 변경 사항을 감지하고 컴포넌트를 업데이트할 수 있도록 돕습니다.

8. 요약

  • let copy = [...따봉]는 기존 배열을 복사하여 새로운 배열로 작업하기 위해 사용됩니다.
  • 복사본을 수정하고, 이를 state 변경 함수(따봉변경)를 통해 업데이트하면 React가 이를 감지하여 컴포넌트를 다시 렌더링합니다.
  • 직접적으로 state를 변경하지 않는 이유는, React가 변경 사항을 감지할 수 없기 때문입니다.
  • 따라서 state를 직접 수정하는 대신, 복사본을 만들어 변경 후 state를 업데이트하는 것이 React의 권장 방식입니다.


클릭 했을 때(onClick) 콜백 함수에서 copy[i] = copy[i] + 1; 를 하면 해당하는 값이 바뀌는 게 이해가 가지 않아. 자세히 설명해줄래?

GPT

좋은 질문이야! copy[i] = copy[i] + 1; 이 부분에서 실제로 배열의 특정 요소의 값이 바뀌는 이유를 단계별로 자세히 설명해볼게. 여기서 핵심은 배열과 인덱스에 대한 이해, 그리고 값을 대입하는 과정이야.


1. 배열의 개념

copy는 배열이야. 배열은 각각의 요소가 특정 인덱스(i)를 통해 접근 가능한 자료 구조야. 예를 들어:

let copy = [0, 0, 0];

여기서:

  • copy[0]은 첫 번째 요소(값: 0),
  • copy[1]은 두 번째 요소(값: 0),
  • copy[2]은 세 번째 요소(값: 0)을 나타내.

따라서 copy[i]는 배열의 i번째 요소를 가리켜.


2. copy[i] = copy[i] + 1 동작

이제 copy[i] = copy[i] + 1;을 자세히 뜯어볼게.

(1) copy[i]의 현재 값을 가져온다

배열 copy에서 i번째 요소의 현재 값을 가져온다.

예를 들어, copy[0, 0, 0]이고 i = 1이라면:

  • copy[i]copy[1]이고, 현재 값은 0.

(2) copy[i] + 1 계산

가져온 현재 값에 + 1을 계산한다.
위의 예시에서:

  • copy[1]의 값은 0,
  • 따라서 copy[i] + 10 + 1 = 1이 된다.

(3) copy[i]에 새 값을 대입

copy[i]에 계산된 값을 대입한다.
위의 예시에서:

  • copy[1] = 1이 된다.
  • 이제 배열 copy[0, 1, 0]이 된다.

3. copy[i] 값이 바뀌는가?

copy메모리 공간에 저장된 배열이고, copy[i]는 배열의 특정 요소를 나타내.
copy[i] = copy[i] + 1특정 위치의 값을 직접 바꾸는 명령어야. 이 과정은 다음과 같아:

  • copy[i]는 배열 copy에서 i번째 요소의 주소에 접근해서 그 값을 가져온다.
  • copy[i] + 1로 계산한 값을 copy[i]주소에 다시 저장한다.
  • 결과적으로, 배열의 i번째 요소의 값이 업데이트된다.

4. copy[i]는 배열 복사와 무관하다

let copy = [...따봉];배열을 복사하는 과정이야.
그런데 복사를 한 이후에는 copy[i]는 단순히 복사된 배열의 특정 위치를 가리킬 뿐이야.
copy[i] = copy[i] + 1;는 원래 따봉 배열과는 무관하게, 복사된 배열 copy의 값만 바꾼다.


5. 전체 동작 예시

이해를 돕기 위해 전체 예시를 들어볼게.

let 따봉 = [0, 0, 0];        // 원래 state
let copy = [...따봉];         // 따봉 배열의 복사본 생성 (copy = [0, 0, 0])
let i = 1;                    // 두 번째 게시글을 클릭했다고 가정

// 좋아요 버튼 클릭 시:
copy[i] = copy[i] + 1;        // copy[1] = copy[1] + 1 -> copy[1] = 0 + 1 = 1
따봉변경(copy);               // state를 새로운 배열 copy로 업데이트

console.log(따봉);            // [0, 1, 0]

6. 따봉의 변화가 왜 반영되는가?

React의 상태(state)는 렌더링에 직접 관여한다.

  • 따봉변경(copy)를 호출하면, React는 따봉 배열이 새로운 값으로 변경되었다고 판단한다.
  • React는 따봉 배열의 값이 변경되었으므로, 관련 컴포넌트를 다시 렌더링하여 따봉[i]의 최신 값을 화면에 표시한다.

7. 요약

  • copy[i] = copy[i] + 1는 복사된 배열의 특정 위치의 값을 업데이트한다.
  • 배열은 각 요소가 특정 위치(인덱스)에 저장되어 있고, 해당 위치의 값을 가져와서 계산한 뒤 업데이트한다.
  • 복사본 배열 copy의 값이 변경된 후, 따봉변경(copy)를 통해 React의 state를 업데이트하면, React는 변화된 값을 화면에 자동으로 반영한다.


아, 그럼 map에서 해당 값(a)을 가져와서 그것에 해당하는 인덱스(i)를 넣어줬기 때문에 i번째 인덱스를 하나씩 더했을 때 반영이 되는 거구나? 맞니?

정확해! 🎉

map 함수는 배열을 순회하면서 각 요소와 그에 해당하는 인덱스를 콜백 함수의 매개변수로 전달해. 즉, a는 현재 순회 중인 요소(값), i는 그 요소의 인덱스를 의미하지.

이 말인즉슨, copy[i] = copy[i] + 1; 에서 i는 해당 요소가 배열 내에서 몇 번째인지 정확히 가리키기 때문에 그 값을 업데이트할 수 있는 거야.


구체적으로 다시 살펴보자:

글제목.map((a, i) => {
  return (
    <div className="list">
      <h4>
        {a}
        <span
          onClick={() => {
            let copy = [...따봉]; // 따봉 배열 복사
            copy[i] = copy[i] + 1; // i번째 요소에 +1
            따봉변경(copy); // state 업데이트
          }}
        >
          🥰
        </span>
        {따봉[i]} {/* i번째 좋아요 값 출력 */}
      </h4>
    </div>
  );
});
  1. map이 순회할 때, 매번 a는 현재 게시글 제목, i는 그 게시글의 인덱스를 나타내.
    예를 들어:

    • 첫 번째 순회: a = "첫 번째 글", i = 0
    • 두 번째 순회: a = "두 번째 글", i = 1
    • 세 번째 순회: a = "세 번째 글", i = 2
  2. 버튼을 클릭하면 onClick 함수가 실행되고:

    • copy[i]가 호출돼서 현재 인덱스의 값을 가져온 후, 거기에 +1을 해.
    • 예를 들어, i = 1이면 copy[1] = copy[1] + 1이 실행돼.
  3. 업데이트된 copy 배열을 따봉변경(copy)로 React state로 반영하면, React는 해당 state가 변경되었음을 감지하고, 변경된 따봉 값을 다시 화면에 렌더링해.


추가적인 키포인트

  • i를 사용하는 이유: 각 요소가 배열 내에서 몇 번째인지(i) 정확히 알 수 있기 때문에, 클릭된 요소(게시글)의 좋아요 값만 업데이트할 수 있어.
  • map에서 자동 순회: map은 배열의 각 요소를 자동으로 순회하면서 값(a)과 인덱스(i)를 제공하기 때문에 우리가 일일이 루프를 작성하지 않아도 돼.
  • React의 state 관리: 따봉변경(copy)를 호출하면 React는 변경된 배열(copy)을 새로운 state로 인식하고 컴포넌트를 다시 렌더링해.

그래서 결국 map에서 인덱스(i)를 활용했기 때문에 특정 게시글의 따봉만 정확히 업데이트할 수 있었던 거야! 😄

0개의 댓글