지금으로부터 2년전인 2022년 3월 29일에 출시된 React 18버전에서는 많은 새로운 기능과 개선 사항들이 적용되었습니다.
주요 변경 사항에 대해 요약을 하면 다음과 같습니다.
Automatic Batching
Transition
Suspense
Client와 Server Side Rendering API 업데이트
Strict Mode 동작 방식 변경
그동안 최신 버전을 사용하고 있었음에도 변화에 대한 명확한 이해가 부족했습니다. 이전 버전 대비 어떤 내용들이 변경되었는지 자세하게 알아보려고 합니다.
Promise / setTimeout / Event Handler 등에서도
Batching
이 일어난다
단어의 뜻을 직역하면 여러 개의 작업들을 묶어서 한번에 처리한다
는 뜻입니다.
아래 코드에서 handleIncrementCount
나 handleDecrementCount
함수 호출 시, state 변화가 2번 일어납니다.
React는 불필요한 렌더링을 피하고자 다수의 상태 업데이트에 대해 일괄적으로 한번만 업데이트가 진행되며 이를 Batching
이라고 합니다.
import React, { useState } from 'react';
const BatchExample: React.FC = () => {
const [ count, setCount ] = useState<number>(0);
const [ checkOdd, setCheckOdd ] = useState<boolean>(false);
const handleIncrementCount = () => {
setCount((cnt) => cnt + 1);
setCheckOdd((ch) => !ch);
// 렌더링 수행
}
const handleDecrementCount = () => {
setCount((cnt) => cnt - 1);
setCheckOdd((ch) => !ch);
// 렌더링 수행
}
return (
<div>
<h1>{count}</h1>
{checkOdd ? <p>짝수입니다.</p> : <p>홀수입니다.</p>}
<button onClick={handleIncrementCount}>증가</button>
<button onClick={handleDecrementCount}>감소</button>
</div>
);
}
export default BatchExample;
17버전 까지는 오직 React Event Handler에 대해서만 Batching
이 적용되었습니다.
그러나, 18버전 부터는 Promises
/ setTimeout
/ native Event Handler
에 대해서도 Batching
이 적용되도록 변경되었습니다.
상태 업데이트 시, 우선순위를 고려
import React, { useState, useTransition, type ChangeEvent } from 'react';
interface ListProps {
items: string[];
}
const List: React.FC<ListProps> = ({ items }) => (
<ul>
{items && items.map((item, idx) => (
<li key={idx}>{item}</li>
))}
</ul>
);
const App: React.FC = () => {
const [inputValue, setInputValue] = useState<string>('');
const [items, setItems] = useState<string[]>([]);
const [isPending, startTransition] = useTransition();
const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value);
};
const handleButtonClick = () => {
startTransition(() => {
setItems((prevItems) => [...prevItems, inputValue]);
setInputValue('');
});
};
return (
<div className='App'>
<input type="text" value={inputValue} onChange={handleInputChange} />
<button onClick={handleButtonClick} disabled={isPending || inputValue.trim() === ''}>Add Item</button>
<List items={items} />
</div>
);
};
export default App;
하위 컴포넌트가 준비되기 전까지 렌더링을 중지
CSR, SSR 더 유연하게 적용
컴포넌트 생명주기의 변경