데이터를 API로 부터 가져와 DOM에 렌더하는 세 가지 접근법
- Fetch-on-Render
function ProfilePage() {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser().then((u) => setUser(u));
}, []);
if (user === null) {
return <p>Loading profile...</p>;
}
return (
<>
<h1>{user.name}</h1>
<ProfileTimeline />
</>
);
}
-
초기 렌더 후 데이터 fetching, 데이터 준비되면 useState를 통한 업데이트
-
컴포넌트가 렌더된 후에 fetching -> waterfall 발생 가능
-
Fetch-Then-Render
// Wrapping all data fetching
function fetchProfileData() {
return Promise.all([fetchUser(), fetchPosts()]).then(([user, posts]) => {
return { user, posts };
});
}
// Using it in our Component
function ProfilePage() {
const [user, setUser] = useState(null);
const [posts, setPosts] = useState(null);
useEffect(() => {
promise.then((data) => {
setUser(data.user);
setPosts(data.posts);
});
}, []);
if (user === null) {
return <p>Loading profile...</p>;
}
return (
<>
<h1>{user.name}</h1>
<ProfileTimeline posts={posts} />
</>
);
}
-
fetching과 컴포넌트를 분리, waterfall 방지
-
fetching 시작, fetching 완료, redering 시작
-
사용자는 그 동안 UI를 볼 수 없음
-
Render as you fetch(Suspense)
- fetching 시작, 렌더링 시작, fetching 완료
- 거의 즉시 렌더링을 시작할 수 있음!!
- try / catch를 통해 로딩 중을 알리기 위해 throw
const resourceCache = {};
const createResource = (asyncTask, key) => {
// 우선 캐시에 키가 존재하는지 체크한다.
// 존재한다면, 캐시된 값을 리턴
if (resourceCache[key]) return resourceCache[key];
// 아니라면 프로미스를 핸들링해야...
throw { promise: asyncTask(), key };
};
-
fallback UI
- React.createElement에서 이걸 catch!
- fallback UI를 보여준다!
const React = {
createElement: (tag, props, ...children) => {
if (typeof tag === "function") {
try {
return tag(props, ...children);
} catch ({ promise, key }) {
// resolved 되었을 때와 rejected 되었을 때를 처리한다.
promise.then((value) => {
resourceCache[key] = value;
reRender();
});
promise.catch((error) => {
console.error(error);
});
// 여기서 VirtualDOM으로 분기한다.
// 이제 바로 렌더가능하다~!!
return { tag: "h2", props: null, children: ["loading your image"] };
}
}
const el = { tag, props, children };
return el;
},
};
-
캐싱
- 이미 값이 있으면 해당 값을 반환, 없으면 프로미스를 던진다!
-
재렌더링