Weekly TIL - Day 7
⭐️ Today's summary
React에서 함수형 컴포넌트를 자세하게 배우며 React Hook에 대해서도 배웠다.
React는 가상 DOM을 사용하여 상태가 변경될 대마다 컴포넌트가 다시 변경될때마다
다시 렌더링 되도록하는데, React Hook이 컴포넌트가 렌더링될 때마다 상태를 유지하고,
업데이트 할 수 있는 메커니즘을 제공한다.
⭐️ Problem
1. useState()를 사용하며 원래의 값을 추적하며 상태 변화를 하는 방법이 헷갈려 정리해 보았다.
2. 여러 컴포넌트에서 사용하는 데이털르 상위 컴포넌트에 state에 저장하고 , 이를
props로 하위 컴포넌트에 전달하는 과정과 이유에 대해서 헷갈려 정리해 보았다.
⭐️ Try
[ useState() 상태값 추적 예제 코드 ]
import React, { useState } from 'react';
const UseStateTest = () => {
// const num = 0;
const [num, setNum] = useState(0);
const onClickPlus = () => {
// num += 1; 현재 상태를 직접 사용해서 변경 -> state변경 x -> 리렌더링 x
setNum(num + 1);
setNum(num + 1);
// 결과적으로 num + 1이 됨 -> 실시간으로 처리되는 것이 아니라 모아두었다가 한번에 처리하는 방식
};
const onClickMius = () => {
setNum((prevNum) => {
return prevNum - 1;
});
setNum((prevNum) => {
console.log('이전 상태 출력 : ', prevNum);
return prevNum - 1;
});
console.log('상태 업데이트 요청');
// 상태가 이전 상태에 의존하는 경우에는
// 항상 상태 업데이트 함수에 콜백을 사용하는 방식(prevNum => prevNum - 1)을 사용해야 한다.
};
return (
<div>
<span>COUNT : {num}</span>
<button onClick={onClickPlus}>+</button>
<button onClick={onClickMius}>-</button>
</div>
);
};
export default UseStateTest;
현재 이 코드에서 Plus가 되는 부분은 setNum(num+1) 처럼 작성하여
state 변수인 num은 값이 고정되어 들어가서 setNum(num+1)이 여러개 있어도 1씩만 증가하게 된다.
하지만 setState 함수에 콜백함수를 넣어 이전 값을 추적할 수 있게 된다.
이는 React가 상태 업데이트를 비동기로 처리하면서 상태 변경 요청을 큐(queue)에 쌓아두고,
콜백함수는 해당 시점의 "최신 상태"를 주기 때문이다.
React에게 setNum((prev) => prev + 1); 이렇게 작성을 하면
React는 " 내가 업데이트를 처리할때 ,
그 이전 상태값(prev)를 줄테니 그걸 기반으로 계산해서 새로운 값을 반환해라"
라고 처리한다 생각하면 된다.
정리하자면
setNum(num + 1 )은 그 시점의 num값 (고정값)을 기반으로 계산된 결과값을 전달한다.
-> 값 추적 불가
setNum(prev => prev + 1 )은 React 내부에서 최신 상태를 함수 인자로 보장해 준다.
-> 안전하고 정확하고 값 추적 가능하다
[ 상위 컴포넌트에 state 저장 예제 코드 ]
import React, { useState } from 'react';
import Toolbar from './Toolbar';
import Grade from './Grade';
const LandingPage = () => {
const [isLogin, setIsLogin] = useState(false);
const onClickLogin = () => {
setIsLogin(true);
};
const onClickLogOut = () => {
setIsLogin(false);
};
return (
<div>
<Toolbar isLogin={isLogin} onClickLogin={onClickLogin} onClickLogOut={onClickLogOut} />
<Grade isLogin={isLogin} />
</div>
);
};
export default LandingPage;
위 코드와 같이 자식 컴포넌트인 <Toolbar/> 와 <Grade/> 컴포넌트에 props를 전달해주는 이유는
LandingPage처럼 여러 자식 컴포넌트에서 공통으로 사용되는 값은 최상위 컴포넌트에서 관리하고,
필요한 자식 컴포넌트에서 props로 전달하는 방식이 React의 단방향 흐름 (one-way-data flow)
즉, 부모 -> 자식 에게 props를 전달하는 구조가 적합하기 때문이다.
그 이유는 유지보수성, 구조적인 설계가 가능하기 떄문이다.
즉, 공통 상태는 부모가 관리하자 ‼️