state는 상태라는 뜻이다. - 파파고 -
useState
는 React Hook 중 하나이다.
useState
는 상태 유지 값과 그 값을 갱신하는 함수를 반환한다.
최초로 렌더링을 하는 동안, 반환된state
는 첫 번째 전달된 인자의 값과 같다.
setState
함수는 state를 갱신할 때 사용한다. 새state
값을 받아 컴포넌트 리렌더링을 큐에 등록한다.
다음 리렌더링 시에useState
를 통해 반환받은 첫 번째 값은 항상 갱신된 최신state
가 된다.
라고 공식 문서에서는 말을 한다.
공식 문서치곤 꽤나 부드러운 표현들로 설명을 잘해 놓았다.
그럼 이 말을 예시 코드와 함께 더욱 이해하기 쉽도록 표현해보자 !
렛쯔고 !
이전 state
를 사용해서 새로운 state
를 계산하는 경우 함수를 setState
로 전달할 수 있으며 그 함수는 이전 값을 받아 갱신된 값을 반환할 것이다 !
말이 조금 어려우니 코드를 한번 살펴보자.
코드로 표현해보자 !
function App() {
const [state, setState] = React.useState(0);
const handleClick = () => {
setState((prev) => prev + 1);
};
return (
<div>
<div>{state}</div>
<button type="button" onClick={handleClick}>
Click Me !
</button>
</div>
);
}
위의 코드를 React에서 실행하게 된다면 버튼을 클릭할 때 마다 state
는 하나씩 증가하게 될 것이다.
useState()
괄호 안에 있는 값은 초기 값이다 !먼저 살펴봐야 할 것은 처음 useState
를 선언 할 때이다.
useState
의 괄호 안에는 state
의 초기 값을 넣을 수 있다.
만약 초기 값을 안넣는다면 undefined
가 나오게 된다.
initialState
라고 해서 초기 값은 함수로 사용이 가능하다 !
state
와 setState
는 뭐가 다른 것인가 ?위에 코드는 state
와 setState
는 useState
의 구조 분해 할당으로
변수를 선언하는 하였다.(기본적으로 저렇게 만듬 !)
state
는 현재 상태(변수)를 의미하는 것이고 setState
는 state
의 값을 변하게 하는 변수라고 생각하면 이해하기 쉽다.
위의 코드를 보면 state
의 초기 값은 0이며 setState
에 이전 값(prev)
은 이전 값 + 1(prev + 1)
로 다시 변하게 된다.
그렇게 state
는 setState
의 값으로 변하게 된다.
setState
는 함수적 갱신을 하게 된다.
함수적 갱신이라... 일단 공식 문서를 알아보자
이전 state
를 사용해서 새로운 state
를 계산하는 경우 함수를 setState
로 전달 할 수 있다. 그 함수는 이전 값을 받아 갱신된 값을 반환할 것이다.
라고 나와 있다.
스크롤하기 귀찮을테니 위에서 본 코드를 그대로 가져와 보겠다.
코드로 표현해보자 !
function App() {
const [state, setState] = React.useState(0);
const handleClick = () => {
setState((prev) => prev + 1);
};
return (
<div>
<div>{state}</div>
<button type="button" onClick={handleClick}>
Click Me !
</button>
</div>
);
}
setState
안에 있는 녀석은 우리가 자주 보았던 '화살표 함수' 이다.
함수적 갱신이란 setState
는 함수로 이전 값을 받아올 수 있다는 것이다.
그래서 안쪽 화살표 함수의 매개 변수 이름이 '이전의' 라는 뜻 previous의 약어이다.
그렇게 이전 값을 받아 + 1을 하니 0 -> 1, 1 -> 2 와 같이 증가하는 모습을 보인 것이다.
useState
는 동기인가 비동기인가 ?!
코드로 표현해보자 !
function App() {
const [state, setState] = React.useState(0);
const handleClick = () => {
setState(state + 1);
setState(state + 1);
setState(state + 1);
};
return (
<div>
<div>{state}</div>
<button type="button" onClick={handleClick}>
Click Me !
</button>
</div>
);
}
setState
에 button
을 클릭 시 state
의 값이 각각 1씩 증가하는 setState
를 무려 3개나 만들어 보았다.
클릭 시 결과는 어떻게 될까 ??
결과는 1개씩 늘어난다. 그렇다 setState
가 비동기적으로 동작하게 된다.
첫 번째 setState
는 state + 1
을 인식하고 그 다음도 state + 1
마지막으로 state + 1
를 인식하는데
동기적 즉 순서대로 코드를 실행하다보니 앞에 있는 setState(state + 1);
두 개는 무시가 되고 마지막 setState(state + 1);
만 동작한 것이다.
그럼 비동기적인 처리는 불가능 한가 ???
그렇지 않다. 바로 함수를 사용하면 되는데
코드로 표현해보자 !
function App() {
const [state, setState] = React.useState(0);
const handleClick = () => {
setState((prev) => prev + 1);
setState((prev) => prev + 1);
setState((prev) => prev + 1);
};
return (
<div>
<div>{state}</div>
<button type="button" onClick={handleClick}>
Click Me !
</button>
</div>
);
}
위의 코드와 같이 함수를 사용하면 비동기적 처리가 가능하다.
그 외 useEffect
의 의존성 배열을 넣으면 비동기적 처리가 가능하다고 한다.
state의 값은 매번 바뀌는데 왜 const이지 ??
우리가 자바스크립트에서 흔히 알고 있는 const
변수는 값의 재할당이 불가능하다. 이는 자바스크립트의 변수에 대해 알고 있는 개발자라면 누구나 다 아는 사실이다.
그런데 어째서 Why state
는 const
로 선언되는데 값을 재할당 할 수 있는가 ??
여기서 우리는 한가지 const
에 대한 미안한 마음으로 오해를 풀어야한다.
state
는 const
변수가 맞지만 재할당하지 않았다.
setState
가 state
의 값을 재할당하는 것처럼 보이나 실제로는 state
의 값이 다시 렌더링 되면서 함수가 다시 실행되기 때문에 새로운 const
변수를 생성하기 때문이다.
그렇기 때문에 state
는 재할당하는 것이 아닌 새로운 const
변수를 만들기에 에러가 일어나지 않는 것이다.
코드로 표현해보자 !
function App() {
console.log('나 다시 렌더링 된다 !')
const [state, setState] = React.useState(0);
const handleClick = () => {
setState((prev) => prev + 1);
setState((prev) => prev + 1);
setState((prev) => prev + 1);
};
return (
<div>
<div>{state}</div>
<button type="button" onClick={handleClick}>
Click Me !
</button>
</div>
);
}
간단하게 실험해보자면 App 함수 안에 console.log()
를 하나 넣어주고
button
을 클릭하여 state
가 변할 때 콘솔창에 렌더링이 된다는 문구를 확인하면 된다.
확인 된다면 버튼을 클릭할 때 마다 App 함수가 새롭게 실행된다는 것을 알 수 있다.
편리한 만큼 내부 코드가 어떻게 짜여 있는지 알기 어려운 것이 라이브러리라고 생각한다.
처음엔 const
에 대해 의심(?)도 했었고 동기적 비동기적인 useState
사용에 대해 조금 살펴보았다.
다행히 수 많은 개발자들이 내가 몰르고 있는 문제를 명쾌하게 블로깅 해준 덕분에 이해하기 쉬웠다.
앞으로 더 많은 Hooks들이 기다리고 있기 때문에 React 공부도 소홀히 해서는 안될 거 같다.