๐ค Chapter 4: ํ์ ์ค๊ณ
๐ฅ ์์ดํ 28. ์ ํจํ ์ํ๋ง ํํํ๋ ํ์ ์ ์งํฅํ๊ธฐโ
ํจ๊ณผ์ ์ผ๋ก ํ์ ์ ์ค๊ณํ๋ ค๋ฉด, ์ ํจํ ์ํ๋ง ํํํ ์ ์๋ ํ์ ์ ๋ง๋ค์ด ๋ด๋ ๊ฒ์ด ๊ฐ์ฅ ์ค์ํฉ๋๋ค.
์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ ๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค. ์ ํ๋ฆฌ์ผ์ด์ ์์ ํ์ด์ง๋ฅผ ์ ํํ๋ฉด, ํ์ด์ง์ ๋ด์ฉ์ ๋ก๋ํ๊ณ ํ๋ฉด์ ํ์ํฉ๋๋ค. ํ์ด์ง์ ์ํ๋ ๋ค์์ฒ๋ผ ์ค๊ณํ์ต๋๋ค.
interface State {
pageText: string;
isLoading: boolean;
error?: string;
}
function renderPage(state: State) {
if (state.error) {
return `Error! Unable to load ${currentPage}: ${state.error}`;
} else if (state.isLoading) {
return `Loading ${currentPage}...`;
}
return `<h1>${currentPage}</h1>\n${state.pageText}`;
}
์ฝ๋๋ฅผ ์ดํด๋ณด๋ฉด ๋ถ๊ธฐ ์กฐ๊ฑด์ด ๋ช
ํํ ๋ถ๋ฆฌ๋์ด ์์ง ์๋ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
ํํธ ํ์ด์ง๋ฅผ ์ ํํ๋ changePage
ํจ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
async function changePage(state: State, newPage: string) {
state.isLoading = true;
try {
const response = await fetch(getUrlForPage(newPage));
if (!response.ok) {
throw new Error(`Unable to load ${newPage}: ${response.statusText}`);
}
const text = await response.text();
state.isLoading = false;
state.pageText = text
} catch (e) {
state.error = '' + e;
}
}
changePage
์๋ ๋ง์ ๋ฌธ์ ์ ์ด ์์ต๋๋ค. ๋ช ๊ฐ์ง ์ ๋ฆฌํด ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ์ค๋ฅ๊ฐ ๋ฐ์ํ์ ๋
state.isLoading
์false
๋ก ์ค์ ํ๋ ๋ก์ง์ด ๋น ์ ธ ์์ต๋๋ค. state.error
๋ฅผ ์ด๊ธฐํํ์ง ์์๊ธฐ ๋๋ฌธ์, ํ์ด์ง ์ ํ ์ค์ ๋ก๋ฉ ๋ฉ์์ง ๋์ ๊ณผ๊ฑฐ์ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ๋ณด์ฌ ์ฃผ๊ฒ ๋ฉ๋๋ค.- ํ์ด์ง ๋ก๋ฉ ์ค์ ์ฌ์ฉ์๊ฐ ํ์ด์ง๋ฅผ ๋ฐ๊ฟ ๋ฒ๋ฆฌ๋ฉด ์ด๋ค ์ผ์ด ๋ฒ์ด์ง์ง ์์ํ๊ธฐ ์ด๋ ต์ต๋๋ค. ์ ํ์ด์ง์ ์ค๋ฅ๊ฐ ๋จ๊ฑฐ๋, ์๋ต์ด ์ค๋ ์์์ ๋ฐ๋ผ ๋๋ฒ์งธ ํ์ด์ง๊ฐ ์๋ ์ฒซ ๋ฒ์งธ ํ์ด์ง๋ก ์ ํ๋ ์๋ ์์ต๋๋ค.
๋ฌธ์ ๋ ๋ฐ๋ก ์ํ ๊ฐ์ ๋ ๊ฐ์ง ์์ฑ์ด ๋์์ ์ ๋ณด๊ฐ ๋ถ์กฑํ๊ฑฐ๋, ๋ ๊ฐ์ง ์์ฑ์ด ์ถฉ๋ํ ์ ์๋ค๋ ๊ฒ์
๋๋ค. State
ํ์
์ isLoading
์ด true
์ด๋ฉด์ ๋์์ error
๊ฐ์ด ์ค์ ๋๋ ๋ฌดํจํ ์ํ๋ฅผ ํ์ฉํฉ๋๋ค. ๋ฌดํจํ ์ํ๊ฐ ์กด์ฌํ๋ฉด render()
์ changePage()
๋ ๋ค ์ ๋๋ก ๊ตฌํํ ์ ์๊ฒ ๋ฉ๋๋ค.
๋ค์์ ์ ํ๋ฆฌ์ผ์ด์
์ ์ํ๋ฅผ ์ข ๋ ์ ๋๋ก ํํํ ๋ฐฉ๋ฒ์
๋๋ค.
interface RequestPending {
state: 'pending';
}
interface RequestError {
state: 'error';
error: string;
}
interface RequestSuccess {
state: 'ok';
pageText: string;
}
type RequestState = RequestPending | RequestError | RequestSuccess;
interface State {
currentPage: string;
requests: {[page: string]: RequestState};
}
์ด๋ฒ ์์ ๋ ์ํ๋ฅผ ๋ํ๋ด๋ ํ์
์ ์ฝ๋ ๊ธธ์ด๊ฐ ์๋ ๋ฐฐ ๊ธธ์ด์ง๊ธด ํ์ง๋ง, ๋ฌดํจํ ์ํ๋ฅผ ํ์ฉํ์ง ์๋๋ก ํฌ๊ฒ ๊ฐ์ ๋์์ต๋๋ค. ํ์ฌ ํ์ด์ง๋ ๋ฐ์ํ๋ ๋ชจ๋ ์์ฒญ์ ์ํ๋ก์, ๋ช
์์ ์ผ๋ก ๋ชจ๋ธ๋ง๋์์ต๋๋ค. ๊ทธ ๊ฒฐ๊ณผ๋ก ๊ฐ์ ๋ renderPage
์ changePage
ํจ์๋ ์ฝ๊ฒ ๊ตฌํํ ์ ์์ต๋๋ค.
function renderPage(state: State) {
const { currentPage } = state;
const requestState = state.requests[currentPage];
switch (requestState.state) {
case 'pending':
return `Loading ${currentPage}...`;
case 'error':
return `Error! Unable to load ${currentPage}: ${requestState.error}`;
case 'ok':
return `<h1>${currentPage}</h1>\n${requestState.pageText}`;
}
}
async function changePage(state: State, newPage: string) {
state.requests[newPage] = { state: 'pending' };
state.currentPage = newPage;
try {
const response = await fetch(getUrlForPage(newPage));
if (!response.ok) {
throw new Error(`Unable to load ${newPage}: ${response.statusText}`);
}
const pageText = await response.text();
state.requests[newPage] = { state: 'ok', pageText };
} catch (e) {
state.requests[newPage] = { state: 'error', error: '' + e };
}
}
์ด๋ฒ ์์ดํ ์ ์ฒ์์ ๋ฑ์ฅํ๋ ๋ชจํธํจ์ ์์ ํ ์ฌ๋ผ์ก์ต๋๋ค. ํ์ฌ ํ์ด์ง๊ฐ ๋ฌด์์ธ์ง ๋ช ํํ๋ฉฐ, ๋ชจ๋ ์์ฒญ์ ์ ํํ ํ๋์ ์ํ๋ก ๋ง์ ๋จ์ด์ง๋๋ค. ์์ฒญ์ด ์งํ ์ค์ธ ์ํ์์ ์ฌ์ฉ์๊ฐ ํ์ด์ง๋ฅผ ๋ณ๊ฒฝํ๋๋ผ๊ณ ๋ฌธ์ ์์ต๋๋ค. ๋ฌดํจ๊ฐ ๋ ์์ฒญ์ด ์คํ๋๊ธด ํ๊ฒ ์ง๋ง UI์๋ ์ํฅ์ ๋ฏธ์น์ง ์์ต๋๋ค.
ํ์ ์ ์ค๊ณํ ๋๋ ์ด๋ค ๊ฐ๋ค์ ํฌํจํ๊ณ ์ด๋ค ๊ฐ๋ค์ ์ ์ธํ ์ง ์ ์คํ๊ฒ ์๊ฐํด์ผ ํฉ๋๋ค. ์ ํจํ ์ํ๋ฅผ ํํํ๋ ๊ฐ๋ง ํ์ฉํ๋ค๋ฉด ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ ์ฌ์์ง๊ณ ํ์ ์ฒดํฌ๊ฐ ์ฉ์ดํด์ง๋๋ค. ์ ํจํ ์ํ๋ง ํ์ฉํ๋ ๊ฒ์ ๋งค์ฐ ์ผ๋ฐ์ ์ธ ์์น์ ๋๋ค. ๋ฐ๋ฉด ํน์ ํ ์ํฉ์์ ์ง์ผ์ผํ ์์น๋ค๋ ์๋๋ฐ, 4์ฅ์ ๋ค๋ฅธ ์์ดํ ๋ค์์ ๋ค๋ฃจ๊ฒ ์ต๋๋ค.
์์ฝโ
- ์ ํจํ ์ํ์ ๋ฌดํจํ ์ํ๋ฅผ ๋ ๋ค ํํํ๋ ํ์ ์ ํผ๋์ ์ด๋ํ๊ธฐ ์ฝ๊ณ ์ค๋ฅ๋ฅผ ์ ๋ฐํ๊ฒ ๋ฉ๋๋ค.
- ์ ํจํ ์ํ๋ง ํํํ๋ ํ์ ์ ์งํฅํด์ผ ํฉ๋๋ค. ์ฝ๋๊ฐ ๊ธธ์ด์ง๊ฑฐ๋ ํํํ๊ธฐ ์ด๋ ต์ง๋ง ๊ฒฐ๊ตญ์ ์๊ฐ์ ์ ์ฝํ๊ณ ๊ณ ํต์ ์ค์ผ ์ ์์ต๋๋ค.