What is State ??
컴포넌트는 사용자와의 상호작용 결과로서 화면을 리렌더링 할 때가 자주 있다. 예를 들면 사용자가 Form에 정보를 입력했다던가, 버튼을 클릭해서 이미지를 보여주게 한다던가 하는 동작 말이다.
이렇게 컴포넌트는 로직의 처리를 위해 특정한 값들을 저장해야 할 필요 가 있으며, React 에서는 이를 state 라고 정의하였다.
state 값이 변경되었을 경우 React 는 해당 컴포넌트를 리렌더링 한다. 따라서 state 의 변화는 컴포넌트의 리렌더링을 유발시키는 요인이라고 볼 수 있다.
function Counter() {
let count = 0;
function increaseCount() {
count += 1;
console.log(count);
}
function decreaseCount() {
count -= 1;
console.log(count);
}
return (
<div>
<button onClick={increaseCount}>+1</button>
<button onClick={decreaseCount}>-1</button>
<p>Count : {count}</p>
</div>
);
}
export default Counter;
해당 코드를 언뜻 보면 평범하게 버튼을 클릭하여 count 값의 증감을 화면에 렌더링하는 코드로 볼 수 있다.
하지만 위 코드는 count 값이 화면에 업데이트 되지 않는다.
여기서 count 는 Js 일반 지역변수로 선언되었다, React의 상태 관리 메커니즘인 useState 를 사용하지 않았기 때문에, React는 이 변수를 추적하거나 변경 사항을 감지하지 않는다.
리렌더링은 React 컴포넌트의 상태(state) 나 속성(props)이 변경될 때 발생한다.
현재 코드에서는 count가 일반 지역 변수로 설정되어 있어, 이 값이 변경되어도 컴포넌트가 다시 렌더링 되지 않는다.
버튼을 클릭하면 increaseCount 나 decreaseCount 함수가 실행되어 count 값을 증기시키거나 감소시킨다.
하지만 이러한 변화는 단지 메모리 내에서의 값 변경일 뿐 React 가 이를 인지하지는 못한다. 그리고 상태나 속성이 변경된 것이 아니기 때문에 리렌더링이 발생하지도 않는다.
그렇기에 console 에는 count의 변경 값이 잘 나오겠지만, 화면에는 초기 렌더링 상태인 0 을 그대로 유지하는 것이다.
이를 해결하기 위해서 useState를 사용하여 count 값을 상태로 선언하고, 상태 변경 함수인 setCount를 사용하여 count 값을 업데이트 해야한다.
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0); // count를 상태로 선언
function increaseCount() {
setCount(count + 1); // 상태 업데이트
}
function decreaseCount() {
setCount(count - 1); // 상태 업데이트
}
return (
<div>
<button onClick={increaseCount}>+1</button>
<button onClick={decreaseCount}>-1</button>
<p>Count: {count}</p> {/* 최신 상태 값이 화면에 업데이트됨 */}
</div>
);
}
export default Counter;
batching 은 React 에서 성능 최적화를 위해 여러 개의 상태 업데이트를 하나의 렌더링 사이클로 묶어서 처리하는 방식을 말한다.
이 방식으로 불필요한 리렌더링을 방지하고 성능을 최적화할 수 있다. 예를 들자면, 여러 개의 setState 호출이 있을 때, 각각의 setState 가 호출될 때 마다 컴포넌트가 리렌더링 되는 것이 아니라, 모든 setState 호출을 하나의 이벤트 루프에서 처리하고 한 번만 리렌더링 하는 것이다.
import React, { useState } from 'react';
function BatchExample() {
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
const handleClick = () => {
// 두 상태 변수를 각각 업데이트합니다.
setCount1(count1 + 1);
setCount2(count2 + 1);
// 일반적으로는 두 개의 상태 업데이트가 각자 컴포넌트를 리렌더링할 수 있지만,
// React의 Batching 덕분에 한 번의 리렌더링만 발생합니다.
console.log('count1:', count1, 'count2:', count2);
};
return (
<div>
<p>Count 1: {count1}</p>
<p>Count 2: {count2}</p>
<button onClick={handleClick}>Increase Counts</button>
</div>
);
}
export default BatchExample;
setState 비동기처리setState 함수가 호출될 때 즉시 상태가 변경되는 것이 아니라, 상태 업데이트 요청이 예약되고 리액트가 최적의 타이밍에 이 요청을 처리한다. 이러한 방식은 컴포넌트가 불필요하게 여러 번 리렌더링 되는 것을 방지한다.import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1); // 상태 업데이트 요청
console.log('Inside handleClick:', count); // 기존의 count 값을 출력
};
return (
<div>
<p>Count: {count}</p>
<button onClick={handleClick}>Increase Count</button>
</div>
);
}
export default Counter;
handleClick 함수를 호출한다
setCount(count + 1) 호출 여기서 함수가 count 값을 1 증가시키도록 요청, 하지만 이 시점에서 상태가 즉시 변경되지는 않음
console.log 실행: console.log는 이전의 count 값을 출력한다. 상태 업데이트가 비동기로 처리되기 때문에 count 는 아직 변경되지 않았기 때문.
리렌더링 리액트가 다음 리렌더링 주기에서 상태 업데이트를 적용하고 컴포넌트를 다시 렌더링 한다.
성능 최적화 : 여러 개의 상태 업데이트 요청을 한 번에 처리하여 리렌더링 횟수를 줄인다. 예를 들어, 연속적으로 여러 번 setState가 호출되면, 리액트는 이를 모아서 한 번만 리렌더링한다.
일관된 UI 상태 유지 : 비동기 업데이트를 통해 컴포넌트가 중간 상태를 보지 않고, 항상 이관된 상태를 유지한다. 만약 상태 업데이트가 동기적으로 처리된다면, 각 상태 변경 후에 컴포넌트가 즉시 리렌더링 되어 UI가 깜빡이거나 불안정해질 수 있음.
Batching(일괄 처리): React는 이벤트 핸들러 내에서 여러 setState 호출이 발생하더라도 이를 일괄 처리하여 한 번의 리렌더링만 발생시키도록 최적화한다.