array, object 자료일 경우 state 수정할 때 약간의 어려움이 존재한다.
/* eslint-disable */
import logo from './logo.svg';
import './App.css';
import { useState } from 'react';
function App() {
//let post = "강남 우동 맛집";
// 자주 변경 될 것 같은 html 부분은 state로 만들어놓기
let [title, modifyTitle] = useState(["여자코트 추천","강남 우동 맛집", "파이썬 독학"]); // [state 에 보관했던 자료, state 변경 도와주는 함수]
let [like, addLike] = useState(0);
return (
<div className="App">
<div className = "black-nav">
<h4>VIN-LOG</h4>
</div>
<button onClick = {() => {modifyTitle(["남자코트 추천","강남 우동 맛집", "파이썬 독학"])}} >글 제목 변경</button>
<div className = "list">
<h4>{title[0]}<span onClick = {() => { addLike(like = like + 1) }}>👍</span>{like}</h4>
<p>12월 9일 발행</p>
</div>
<div className = "list">
<h4>{title[1]}<span onClick = {() => {addLike(like = like + 1)}}>👍</span> {like}</h4>
<p>12월 9일 발행</p>
</div>
<div className = "list">
<h4>{title[2]} <span onClick = {() => {addLike(like = like + 1)}}>👍</span> {like}</h4>
<p>12월 9일 발행</p>
</div>
</div>
);
}
export default App;
글 제목 변경이라는 버튼을 하나 만들어 놓고 해당 버튼 클릭 시 state를 이용하여 남자코트 추천 이라는 제목을
여자 코트 추천이라는 제목으로 바뀌도록 해두었다.
하지만 위의 코드는 state에 들어있는 전체 배열을 그대로 modifyTitle 이라는 함수에 넣어 변경되지 않는 부분까지
매개변수로 넣어주어야 하기에 확장성이 좋지 못하다
만약 글이 100개 였다면 코드 가독성이 매우 떨어졌을 것임
따라서 state를 다 복붙하지 않고 첫 글 제목만 가져와서 state 변경 함수에 집어 넣는 식으로 코드를 변경해야할 필요가 있다.
<button onClick = {() => {
title[0] = '여자코트 추천';
modifyTitle(title)}} >글 제목 변경</button>
<div className = "list">
이런식으로 인덱싱을 사용해서 첫 번째 원소만을 변경하여 state 변경 함수에 넣어주거나
<button onClick = {() => {
let copy = title;
copy[0] = '여자코트 추천';
modifyTitle(copy)}} >글 제목 변경</button>
<div className = "list">
복사본을 만들어 복사본을 변경하여 state 변경함수에 넣어주는 방법도 있는데
원본 데이터를 직접 조작하는 것 보다는 기존 값을 보존해주는 식으로 코드를 짜는게 더 낫기 때문에
후자가 좀 더 안전하다.
그러나 이렇게 하면 버튼을 눌러도 수정이 되지가 않는데
이는 state 변경 함수의 동작 원리와 관련되어 있다
State 변경 함수 동작 원리
State 변경 함수를 쓸 때 기존 state 와 신규 state 를 비교해보고 같으면 state를 변경하지 않는다.
위 코드에서도 modifyTitle(copy) 해줘도 copy == 기존 state 여서 변경을 안해준 것이다
copy[0] = "여자코트 추천" 해줬는데 왜 기존 state 랑 같으냐고?
자바스크립트는 array/object 자료를 만들면 ex) let arr = [1,2,3]
[1,2,3] 이라는 array 는 RAM 에다가 저장하고 let arr 에는 그 array 가 어디 있는지 가리키는 화살표(주소) 만 담겨있다.
let arr1 = [1,2,3]
let arr2 = arr1
그래서 위 처럼 arr1에 있던 자료를 arr2로 복사하게 되면 화살표 값이 복사가 되는거고 [1,2,3] 이라는 값을 각각 별도로
가지는게 아니라 하나의 객체를 두 변수가 공유하며 화살표로 가리키고 있게 된다.
그래서 copy[0] = '여자코트 추천' 을 해주면 title 배열의 첫 번째 요소도 변경되기는 하지만!!
컴퓨터는 같은 화살표를 가지고 있는 (같은 주소를 참조하고 있는) 변수 끼리는 등호로 비교해도 같다고 나온다
arr1 == arr2 // true 라는 소리
따라서 State 변경함수의 동작 원리에 따라 copy 와 기존 state가 같다고 생각하기 때문에 값을 변경시켜주지 않는 것임
let copy = [...title]
copy[0] = '여자코트 추천'
modify(copy)
이러면 잘된다
spread operator 라는 문법인데 괄호를 벗겨준다 괄호를 벗겨준다는게 무슨 말인지 궁금해서 찾아보니
배열의 요소를 개별적으로 꺼내서 새로운 배열에 넣는 것과 같다는 의미였다.
이렇게 하게되면 같은 array/object 를 공유하는 것이 아닌 독립적인 array 복사본을 생성해줄 수 있다!
이러면 이제 copy 와 title 을 비교했을 때 두 화살표가 다르기 때문에 값을 업데이트 시켜줄 수 있다.
요약
리액트에서 array/object 를 수정하고 싶으면 독립적인 카피본을 만들어서 수정하는게 좋다.
[...기존 state]
{...기존 state}
이렇게 하면 독립적인 복사본이 생성
'react' 카테고리의 다른 글
[react] 리액트 환경에서 동적인 UI 만드는 법 (1) | 2024.12.10 |
---|---|
[react] Component : 많은 div 들을 한 단어로 줄이고 싶을 때 (0) | 2024.12.10 |