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>12월 6일 발행</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>12월 6일 발행</p>
</div>
);
})"
이전 코드에서 따봉변경(따봉+1)을 하는 건 이해가 됐는데,
이후 코드에서 copy[i] = copy[i]+1을 하면 이것과 동일한 결과가 나오는 게 왜 그런지 궁금해서 물어봤다.
웃긴거 : GPT가 질문 칭찬해줌ㅋㅋㅋㅋㅋㅋ
좋아요! 질문이 아주 훌륭합니다. 기존 코드와 수정한 코드에서 동작 원리를 이해하려면, React의 state 업데이트 방식과 값의 참조와 복사에 대해 이해해야 합니다. 아래에서 하나씩 차근차근 설명할게요.
따봉변경(따봉 + 1)이 어떻게 동작했는가?<span onClick={() => { 따봉변경(따봉 + 1) }}>
🥰
</span> {따봉}
따봉)일 때 작동하는 방식입니다.따봉은 단순히 숫자(0, 1, 2, ...)이고, 따봉변경은 이를 업데이트하는 함수입니다.따봉 + 1은 따봉 값을 1 증가시켜서, 새로운 값으로 업데이트합니다.따봉 상태를 공유하므로, 어떤 게시글의 "좋아요"를 눌러도 모든 게시글이 동일한 따봉 값을 표시하게 됩니다.따봉을 배열로 사용한 이유문제는, 게시글별로 독립적인 따봉 값을 저장하고 싶다는 점입니다. 이를 해결하기 위해, 따봉을 배열로 만들어 각 게시글마다 별도의 좋아요 카운트를 관리할 수 있도록 했습니다.
let [따봉, 따봉변경] = useState([0, 0, 0]); // 게시글마다 좋아요 수를 저장
위 코드에서 따봉은 배열입니다. 예를 들어, [0, 0, 0]이라면:
따봉[0]: 첫 번째 게시글의 좋아요 수.따봉[1]: 두 번째 게시글의 좋아요 수.따봉[2]: 세 번째 게시글의 좋아요 수.React에서는 state를 직접 변경하면 안 됩니다. 예를 들어, 아래처럼 작성하면 오류를 유발할 수 있습니다:
따봉[i] = 따봉[i] + 1; // 직접적으로 state를 변경
따봉변경(따봉); // state 업데이트
React의 state는 변경이 감지될 때만 컴포넌트를 다시 렌더링합니다. 만약 state를 직접 변경하면 React는 "state가 변경되었는지"를 알 수 없어서 다시 렌더링이 발생하지 않을 수도 있습니다. 이는 React가 상태 변경을 감지하기 위해 === 비교를 수행하기 때문입니다.
let copy = [...따봉]이란?let copy = [...따봉]는 따봉 배열의 복사본을 만드는 코드입니다.
[...따봉]은 spread 문법으로, 기존 배열의 값을 새 배열로 복사합니다.따봉)은 그대로 유지되고, 복사본(copy)에서 작업을 수행할 수 있습니다.let copy = [...따봉]; // 따봉 배열 복사
copy[i] = copy[i] + 1; // i번째 게시글의 좋아요 수 증가
따봉변경(copy); // 복사본을 새로운 state로 설정
copy를 만들고, copy[i]의 값을 수정합니다.copy를 따봉변경을 통해 React state로 업데이트합니다.copy)을 이전 상태와 비교(===)하여 "state가 변경되었다"는 것을 감지하고, 컴포넌트를 다시 렌더링합니다.따봉[i] = 따봉[i] + 1과 copy[i] = copy[i] + 1의 차이점따봉[i] = 따봉[i] + 1 (잘못된 방식)따봉을 수정하는 방식입니다.let copy = [...따봉]; copy[i] = copy[i] + 1; (올바른 방식)copy)을 생성하여, 복사본의 값을 변경합니다.React에서 state를 변경할 때는 항상 불변성(immutability)을 유지해야 합니다.
let copy = [...따봉]는 기존 배열을 복사하여 새로운 배열로 작업하기 위해 사용됩니다.따봉변경)를 통해 업데이트하면 React가 이를 감지하여 컴포넌트를 다시 렌더링합니다.클릭 했을 때(onClick) 콜백 함수에서 copy[i] = copy[i] + 1; 를 하면 해당하는 값이 바뀌는 게 이해가 가지 않아. 자세히 설명해줄래?
좋은 질문이야! copy[i] = copy[i] + 1; 이 부분에서 실제로 배열의 특정 요소의 값이 바뀌는 이유를 단계별로 자세히 설명해볼게. 여기서 핵심은 배열과 인덱스에 대한 이해, 그리고 값을 대입하는 과정이야.
copy는 배열이야. 배열은 각각의 요소가 특정 인덱스(i)를 통해 접근 가능한 자료 구조야. 예를 들어:
let copy = [0, 0, 0];
여기서:
copy[0]은 첫 번째 요소(값: 0),copy[1]은 두 번째 요소(값: 0),copy[2]은 세 번째 요소(값: 0)을 나타내.따라서 copy[i]는 배열의 i번째 요소를 가리켜.
copy[i] = copy[i] + 1 동작이제 copy[i] = copy[i] + 1;을 자세히 뜯어볼게.
copy[i]의 현재 값을 가져온다배열 copy에서 i번째 요소의 현재 값을 가져온다.
예를 들어, copy가 [0, 0, 0]이고 i = 1이라면:
copy[i]는 copy[1]이고, 현재 값은 0.copy[i] + 1 계산가져온 현재 값에 + 1을 계산한다.
위의 예시에서:
copy[1]의 값은 0,copy[i] + 1은 0 + 1 = 1이 된다.copy[i]에 새 값을 대입copy[i]에 계산된 값을 대입한다.
위의 예시에서:
copy[1] = 1이 된다.copy는 [0, 1, 0]이 된다.copy[i] 값이 바뀌는가?copy는 메모리 공간에 저장된 배열이고, copy[i]는 배열의 특정 요소를 나타내.
copy[i] = copy[i] + 1는 특정 위치의 값을 직접 바꾸는 명령어야. 이 과정은 다음과 같아:
copy[i]는 배열 copy에서 i번째 요소의 주소에 접근해서 그 값을 가져온다.copy[i] + 1로 계산한 값을 copy[i]의 주소에 다시 저장한다.i번째 요소의 값이 업데이트된다.copy[i]는 배열 복사와 무관하다let copy = [...따봉];은 배열을 복사하는 과정이야.
그런데 복사를 한 이후에는 copy[i]는 단순히 복사된 배열의 특정 위치를 가리킬 뿐이야.
copy[i] = copy[i] + 1;는 원래 따봉 배열과는 무관하게, 복사된 배열 copy의 값만 바꾼다.
이해를 돕기 위해 전체 예시를 들어볼게.
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]
React의 상태(state)는 렌더링에 직접 관여한다.
따봉변경(copy)를 호출하면, React는 따봉 배열이 새로운 값으로 변경되었다고 판단한다.따봉 배열의 값이 변경되었으므로, 관련 컴포넌트를 다시 렌더링하여 따봉[i]의 최신 값을 화면에 표시한다.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>
);
});
map이 순회할 때, 매번 a는 현재 게시글 제목, i는 그 게시글의 인덱스를 나타내.
예를 들어:
a = "첫 번째 글", i = 0a = "두 번째 글", i = 1a = "세 번째 글", i = 2버튼을 클릭하면 onClick 함수가 실행되고:
copy[i]가 호출돼서 현재 인덱스의 값을 가져온 후, 거기에 +1을 해.i = 1이면 copy[1] = copy[1] + 1이 실행돼.업데이트된 copy 배열을 따봉변경(copy)로 React state로 반영하면, React는 해당 state가 변경되었음을 감지하고, 변경된 따봉 값을 다시 화면에 렌더링해.
i를 사용하는 이유: 각 요소가 배열 내에서 몇 번째인지(i) 정확히 알 수 있기 때문에, 클릭된 요소(게시글)의 좋아요 값만 업데이트할 수 있어.map에서 자동 순회: map은 배열의 각 요소를 자동으로 순회하면서 값(a)과 인덱스(i)를 제공하기 때문에 우리가 일일이 루프를 작성하지 않아도 돼.따봉변경(copy)를 호출하면 React는 변경된 배열(copy)을 새로운 state로 인식하고 컴포넌트를 다시 렌더링해.그래서 결국 map에서 인덱스(i)를 활용했기 때문에 특정 게시글의 따봉만 정확히 업데이트할 수 있었던 거야! 😄