티스토리 뷰
🔎 state ?
React에서 state는 내부에서 변경될 수 있는 값을 의미합니다.
따라서 컴포넌트가 렌더링 되고 난 후 값이 변경되어 재렌더링될 가능성이 있는 값들은 state로 선언합ㄴ디ㅏ.
state는 값은 state함수를 통해 갈아끼워진다
이 말이 무슨 뜻인지는 코드로 알아봅시다.
function Test() {
const [ name, setName ] = useState('');
const settingName = () => {
// name = '홍길동'; => 이렇게 사용X
setName('홍길동');
}
return(
<div>{name}</div>
)
}
위 코드아 같이 state값인 name을 직접적으로 바꾸지 말라는 것인데,
무조건 setName(), state함수를 통해 값을 바꿔야 한다.
state 값이 객체나 배열일 경우?
앞서 state 값은 state함수를 통해 갈아끼워지는 것이라고 적었는데요.
이는 객체나 배열일 경우에 더 와닿는 거 같습니다.
아래 코드를 통해 이해해 봅시다.
import {useState} from 'react';
function ArrayAndObject() {
const [member, setMember] = useState({name: '홍길동', age: 25, gender: 'M'});
const updateMember = () => {
// member.name = '고길동'; => 변경X
let temp = member;
temp.name = '고길동';
setMember(temp);
};
return (
<div>
<p>{member}</p>
</div>
);
}
export default ArrayAndObject;
member.name = '고길동' 처럼 state값에 직접 접근하여 데이터를 변경하려 하는 것은 안됩니다.
그럼 위 코드처럼 실행하면 잘 실행될까요? 아닙니다.
얕은 복사(Shallow Copy), 깊은 복사(Deep Copy)
1. 얕은 복사(Shallow Copy)
얕은 복사란, 위의 코드에서 let temp = member; 가 얕은 복사의 예시입니다.
이렇게 하면 temp도 member와 같이 동일한 객체(값, 메모리 주소)를 가집니다.
변수가 선언되면 메모리에 할당이 되는데
얕은 복사를 사용하면(let temp = member;) 두 변수가 동일한 메모리 주소를 가리리게 된다.
즉, temp를 변경할 경우 member도 변경이 된다.
따라서 temp와 member는 동일한 메모리 주소를 가리키므로 temp.name = '고길동'을 하면
member.name도 고길동으로 바뀌는 것입니다.
이렇게 되면 member라는 state값을 직접적으로 바꾸는 것과 다름이 없습니다.
그럼 어떻게 해야할까요? 깊은 복사를 해야 합니다.
2. 깊은 복사
동일한 값을 가지지만 다른 메모리 주소를 가리킨다.
얕은 복사와는 다르게 다른 메모리 주소를 가집니다.
따라서 위의 예로 설명해보면 member를 깊은 복사하여 나온 결과가 temp라면, temp와 member는 서로 전혀 다른 객체지만 같은 값을 가진 것입니다.
즉, temp를 바꾸더라도 member의 값들은 바뀌지 않는 것이죠!
그렇다면 setMember(temp)가 우리가 원하는 대로 잘 동작할 것입니다.
temp 값만을 바꿔서 member의 값을 갈아끼우면 되는 것이기 떄문입니다.
깊은 복사 사용 방법
1. state 값이 배열일 경우
방법1. concat : 새로운 데이터를 기존 배열에 더해 새로운 배열을 만든다
let tempArray = originalArray.concat(newData);
방법2. Array.from : 내장 객체인 Array의 내장 함수 from()을 사용하여 복사본을 생성한다
let tempArray = Array.from(originalArray);
간단한 예제
import {useState} from 'react';
function ArrayAndObject() {
const [member, setMember] = useState([
{name: '이병건', age: 23, gender: 'M'},
]);
const addMember = () => {
let tempArray = member.concat({name: '주호민', age: 24, gender: 'M'});
setMember(tempArray);
};
const deleteMember = () => {
let tempArray = Array.from(member);
tempArray.splice(0, 1);
setMember(tempArray);
};
return <div>{member}</div>;
}
export default ArrayAndObject;
2. state 값이 객체일 경우
방법1. Object.assign : 단순히 복사도 가능하지만, concat의 기능도 수행 가능
let tempObj = Object.assign({}, orginalObj);
방법2. 전개 연산자(Spread Operator) : 전개 연산자를 사용하여 값을 가져와서 새로운 변수에 저장
let tempObj = {...originalObj}
간단한 예시
import {useState} from 'react';
function Object() {
const [member, setMember] = useState({name: '홍길동', age: 23});
const onEditInfo = () => {
const tempObj = {...member};
tempObj.name = '고길동';
tempObj.age = 30;
setMember(tempObj);
};
return (
<div>
<button onClick={onEditInfo}>변경</button>
<h3>name : {member.name}</h3>
<h3>age : {member.age}</h3>
</div>
);
}
export default Object;
지금 전개 연산자를 통해 값을 가져와 새로운 변수에 저장해서
그 다음 setMember로 값을 갈아끼워주었습니다.
깊은 복사가 잘 되었는지 확인해 봅시다.
tempObj에서 깊은 복사가 되지 않았다면 state가 제대로 바뀌지 않아 화면에도 보이지 않았을 것입니다.
'프론트엔드 > React' 카테고리의 다른 글
[React] useCallback - 함수를 재사용하자 (0) | 2023.02.13 |
---|---|
[React] useMemo - 연산한 값을 재사용하자 (0) | 2023.02.13 |
[React] SOLID 원칙에 기초한 React 코드 작성법 (0) | 2023.02.11 |
[React] Outlet으로 레이아웃 구성하기, url에 따라 다른 레이아웃 적용하기 (0) | 2023.02.11 |
[React] 프로젝트 공용 컴포넌트 관리 - 한번만 작성하고 import해서 쓰자 (0) | 2023.02.07 |
- Total
- Today
- Yesterday
- 타입스크립트
- react-query
- jest
- CSS
- 머신러닝
- HTML
- react
- TypeScript
- next.js
- 프론트엔드 공부
- 프로젝트 회고
- 파이썬
- rtl
- 프론트엔드
- 리액트
- 데이터분석
- 인프런
- 리액트 훅
- 스타일 컴포넌트 styled-components
- testing
- 프론트엔드 기초
- 자바
- Python
- JSP
- frontend
- 자바스크립트
- styled-components
- 자바스크립트 기초
- 딥러닝
- 디프만
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |