- 불변성
- 클로저(자바스크립트개념)
- prop-drilling
불변성
(1) 불변성이란?
불변성이란 메모리에 있는 값을 변경할 수 없는 것을 말한다. 자바스크립트의 데이터 형태중에 원시 데이터는 불변성이 있고, 원시 데이터가 아닌 객체, 배열, 함수는 불변성이 없다.
(2) 변수를 저장하면, 메모리에 어떻게 저장이 될까?
만약 우리가 let number = 1 이라고 선언을 하면, 메모리에는 1 이라는 값이 저장된다. 그리고 number 라는 변수는 메모리에 있는 1의 주소값을 참조한다. 그리고 이어서 let secondNumber = 1 이라고 다른 변수를 선언을 했다고 가정해보자. 이때도 자바스크립트는 이미 메모리에 생성되어 있는 1이라는 값을 참조한다. 즉, number와 secondNumber는 변수의 이름은 다르지만, 같은 메모리의 값을 바라보고 있는 것이다. 그래서 우리가 콘솔에 number === secondNumber 를 하면 true가 보입니다.
하지만, 원시데이터가 아닌 값(객체, 배열, 함수)는 이렇지 않다. let obj_1 = {name: ‘kim’} 이라는 값을 선언하면 메모리에 obj_1이 저장이 된다. 그리고 이어서 let obj_2 = {name: ‘kim’} 이라고 같은 값을 선언하면 obj_2라는 메모리 공간에 새롭게 저장이 된다. 그래서 obj_1 === obj2 는 false 가 되는 것이다.
(3) 데이터를 수정하면 어떻게 될까?
다시 원시데이터로 돌아와서 만약에 기존에 1이던 number를 number = 2 라고 새로운 값을 할당하면 메모리에서는 어떻게 될까? 원시 데이터는 불변성이 있다. 즉, 기존 메모리에 저장이 되어 있는 1이라는 값이 변하지 않고, 새로운 메모리 저장공간에 2가 생기고 number라는 값을 새로운 메모리 공간에 저장된 2를 참조하게 된다. 그래서 secondNumber를 콘솔에 찍으면 여전히 1이라고 콘솔에 보인다.
number와 secondNumber는 각각 다른 메모리 저장공간을 참조하고 있기 때문이다.
obj_1를 수정해보자. obj_1.name = ‘park’ 이라고 새로운 값을 할당하면 어떻게 될까? 객체는 불변성이 없다. 그래서 기존 메모리 저장공간에 있는 {name: ‘kim’} 이라는 값이 {name : ‘park’} 으로 바뀌어 버린다. 즉, 원시데이터는 수정을 했을 때 메모리에 저장된 값 자체는 바꿀 수 없고, 새로운 메모리 저장공간에 새로운 값을 저장하는 것이고, 원시데이터가 아닌 데이터는 수정했을 때 기존에 저장되어 있던 메모리 저장공간의 값 자체를 바꿔버리는 것이다.
(4) 왜 리액트에서는 원시데이터가 아닌 데이터의 불변성을 지켜주는 것을 중요시할까?
리액트에서는 화면을 리레더링 할지 말지 결정할 때 state의 변화를 확인합니다. (state가 변했으면 리렌더링 하기때문)
React는 state가 변했는지 변하지 않았는지 확인하기 위해 state의 변화 전, 후의 메모리 주소를 비교하는 방법을 사용한다. 그래서 만약 리액트에서 원시데이터가 아닌 데이터를 수정할 때 불변성을 지켜주지 않고, 직접 수정을 가하면 값은 바뀌지만 메모리주소는 변함이 없게 된다. 그래서 개발자가 값은 바꿨지만 리액트는 state가 변했다고 인지하지 못하므로, 결국 마땅히 일어나야 할 리렌더링이 일어나지 않게된다.
(5) 리액트 불변성 지키기 예시
setState 사용할 때 배열의 불변성을 지켜주기 위해서는
직접 수정을 가하지 않고 spread 연산자를 사용해서 기존의 값을 복사하고, 그 이후에 값을 수정하는 식으로 구현해야한다.
이렇게 하면 새로운 배열과 객체를 만드는 것이므로, State의 변화를 감지할 수 있게되고 결국 re-rendering할 수 있다.
import React, { useState } from "react";
function App() {
const [dogs, setDogs] = useState(["말티즈"]);
function onClickHandler() {
// spread operator(전개 연산자)를 이용해서 dogs를 복사한다.
// 그리고 나서 항목을 추가한다.
setDogs([...dogs, "시고르자브르종"]);
}
console.log(dogs);
return (
<div>
<button onClick={onClickHandler}>버튼</button>
</div>
);
}
export default App;
useState
바닐라자바스크립트문법만으로는 UI에 데이터를 갱신하고 화면에 업데이트해줄 수 없기때문에 React Hooks에서 제공하는 useState() 함수를 사용해야한다.
const [<상태 값 저장 변수>, <상태 값 갱신 함수>] = useState(<상태 초기 값>);
첫 번째 원소는 상태 값을 저장할 변수이고, 두번 째 원소는 해당 상태 값을 갱신할 때 사용할 수 있는 함수이다.
그리고 useState() 함수에 인자로 해당 상태의 초기 값을 넘길 수 있다.
React에서는 re-redering조건이 있는데 이 조건에 충족하지 않아, console.log에는 num의 값이 1씩 커지는 모습이 보임에도 불구하고
화면에는 출력되지 않는 것이다.
자바스크립트 클로저 공부하고나서 다시볼 부분 - [4.16 useState 유의할점]
prop drilling 에제
import React, { useState } from 'react';
import './App.css';
import Counter from './components/Counter';
export default function AppCounter() {
const [count, setCount] = useState(0);
const handleClick = () => setCount((prev) => prev + 1);
return (
<div className='container'>
<div className='banner'>
Total Count: {count} {count > 10 ? '🔥' : '❄️'}
</div>
<div className='counters'>
<Counter total={count} onClick={handleClick} />
<Counter total={count} onClick={handleClick} />
</div>
</div>
);
}
'React(Docs) > React(Practice)' 카테고리의 다른 글
AppMentors_배열상태 관리(불변성, map, spread연산자) (0) | 2022.12.11 |
---|---|
AppXY_객체initialState(transform, onPointerMove) (0) | 2022.12.10 |
AppProducts_useEffect(토글, fetch, 삼항연산자, re-rendering조건) (0) | 2022.12.09 |
React JSX 문법 정리 (0) | 2022.12.05 |
React 큰그림 (0) | 2022.12.04 |