Concurrent 렌더링은 React 18에서 도입된 핵심 기능으로, 렌더링 작업을 중단, 재개, 우선순위 지정할 수 있게 해줍니다. 이를 통해 사용자 인터페이스의 반응성을 크게 향상시킬 수 있습니다.
주요 특징:
AS-IS
import React, { useState, useEffect } from 'react';
function SearchComponent({ searchTerm }) {
const [results, setResults] = useState([]);
useEffect(() => {
const fetchResults = async () => {
const response = await fetch(`/api/search?q=${searchTerm}`);
const data = await response.json();
setResults(data);
};
fetchResults();
}, [searchTerm]);
return (
<ul>
{results.map(item => (
<li key={item.id}>{item.title}</li>
))}
</ul>
);
}
TO-BE
import React, { useState, useTransition } from 'react';
function SearchComponent({ searchTerm }) {
const [results, setResults] = useState([]);
const [pending, startTransition] = useTransition();
useEffect(() => {
startTransition(async () => {
const response = await fetch(`/api/search?q=${searchTerm}`);
const data = await response.json();
setResults(data);
});
}, [searchTerm]);
return (
<>
{pending && <p>Searching...</p>}
<ul>
{results.map(item => (
<li key={item.id}>{item.title}</li>
))}
</ul>
</>
);
}
AS-IS (React 17)
import React, { useState } from 'react';
function TabComponent() {
const [activeTab, setActiveTab] = useState('home');
const renderTabContent = () => {
switch (activeTab) {
case 'home':
return <HomeContent />;
case 'profile':
return <ProfileContent />;
case 'settings':
return <SettingsContent />;
default:
return null;
}
};
return (
<div>
<div>
<button onClick={() => setActiveTab('home')}>Home</button>
<button onClick={() => setActiveTab('profile')}>Profile</button>
<button onClick={() => setActiveTab('settings')}>Settings</button>
</div>
{renderTabContent()}
</div>
);
}
function HomeContent() {
// 복잡한 렌더링 로직
return <div>Home Content</div>;
}
function ProfileContent() {
// 복잡한 렌더링 로직
return <div>Profile Content</div>;
}
function SettingsContent() {
// 복잡한 렌더링 로직
return <div>Settings Content</div>;
}
TO-BE (React 18 with Concurrent Features)
import React, { useState, useTransition } from 'react';
function TabComponent() {
const [activeTab, setActiveTab] = useState('home');
const [isPending, startTransition] = useTransition();
const handleTabChange = (tab) => {
startTransition(() => {
setActiveTab(tab);
});
};
const renderTabContent = () => {
switch (activeTab) {
case 'home':
return <HomeContent />;
case 'profile':
return <ProfileContent />;
case 'settings':
return <SettingsContent />;
default:
return null;
}
};
return (
<div>
<div>
<button onClick={() => handleTabChange('home')}>Home</button>
<button onClick={() => handleTabChange('profile')}>Profile</button>
<button onClick={() => handleTabChange('settings')}>Settings</button>
</div>
{isPending ? <div>Loading...</div> : renderTabContent()}
</div>
);
}
// HomeContent, ProfileContent, SettingsContent 컴포넌트는 이전과 동일
useTransition을 사용하여 검색 작업을 비차단적으로 만들어 UI의 반응성을 유지합니다.