React 공식문서 - 데이터를 가져오기 위한 Suspense (실험 단계)
const ProfilePage = React.lazy(() => import('./ProfilePage')); // 지연 로딩
// 프로필을 불러오는 동안 스피너를 표시합니다
<Suspense fallback={<Spinner />}>
<ProfilePage />
</Suspense>
ProfilePage
에서는 비동기 처리가 진행되고 있다. 비동기 처리가 이루어지는 동안, Spinner
컴포넌트가 랜더된다. 사용자는 ProfilePage
컴포넌트에서 데이터가 없는 상태에서 기다리는 것이 아닌, spinner가 도는 것 같은 효과를 이용하기 때문에 친절한 웹을 만들 수 있도록 도와준다.
비동기 처리가 끝나면 리랜더링을 진행하여
ProfilePage
를 사용자에게 보여준다.
Suspense는 그저 컴포넌트가 읽어들이고 있는 데이터가 아직 준비되지 않았다고 사용자에게, 그리고 리액트에게 알려줄 수 있는 매커니즘이다.
fetch와 같은 것으로 Suspense를 대체할 수 없다. Relay API, SWR 와 같은 data fetching 라이브러리와 함께 사용할 수 있다.
Suspense는 데이터를 동기적으로 읽어오는 것처럼 느껴지게 해준다.
자바스크립트에서 경쟁상태란? 여러 개의 비동기 작업의 결과가 하나의 Dom 객체에 반영되는 상황이 있는 경우다.
예제)
1. 미키, 주모, 심바, 파노, 카일 5개의 버튼이 있고 각 버튼을 누르면 크루에 대한 프로필을 서버에 요청한다.
2. 프로필 요청 응답을 앱이 받으면 해당 정보를 컴포넌트에 업데이트한다.
3. 빠른 속도로 누른다고 생각하면 마지막에 누른 버튼과 컴포넌트의 정보가 일치할 수 있을까?"NO"
이유는 버튼을 누른 순서대로 프로필 요청에 대한 응답이 도착하고 순서대로 동작하길 바란다는 것은 개발자의 생각이라는 것이다.그래서 Suspense는 이를 어떻게 해결했을까?
- 이전 :
A 프로필 요청 ➡️ 로딩 UI랜더 ➡️ A프로필 응답 ➡️ Profile 응답
- Suspense 이용 :
A 프로필 요청 ➡️ Profile 컴포넌트에 A프로필 요청 리소스 반영 ➡️ Suspense에 의해 A 요청에 대한 로딩 UI 변경 ➡️ 요청 리소스로 A 프로필에 대한 응답이 들어옴 ➡️ 반영
⏤ 동기적으로 처리하는 것처럼 보인다.Reference | 사용자 경험 개선 1편 - react suspense
우리가 자주 사용하는 리액트 생명주기에 라이프 사이클 중에 ComponentDidMount를 호출할 수 있도록 해주는 UseEffect()라는 훅을 이용한다
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 />
</>
);
}
function ProfileTimeline() {
const [posts, setPosts] = useState(null);
useEffect(() => {
fetchPosts().then(p => setPosts(p));
}, []);
if (posts === null) {
return <h2>Loading posts...</h2>;
}
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
ProfilePage
호출이 된다. <p>Loading profile...</p>
이 호출된다.비동기 처리의 장점이 무엇이었을까? 비동기 처리 작업을 하는 동안 다른 작업도 병렬적으로 처리할 수 있음이다. 그럼에도 위와 같은 코드는 코드상의 한계로 waterfall
현상으로 병렬적으로 처리하지 못한다.
개인적으로 GraphQL을 사용하고 있지 않기 때문에 패스했다.
SWR을 사용한 useRequest, 리엑트 Data Fetching
데이터를 가져오기 위한 리액트 훅, SWR
공식 문서에서 Suspense와 관련된 내용만 읽었습니다.
Suspense 기능 활성화하면 랜더링시 data 가 항상 준비된다.
function Profile () { const { data } = useSWR('/api/user', fetcher, { suspense: true }) }
여기서 data는 절대 undefined가 들어올 수 없다. 만약 조건부 가져오기를사용한다면 요청이 일시 중단 된 경우에만 undefined가 될 수 있다.
const { data } = useSWR(isReady ? '/api/user' : null, fetcher, { suspense: true })
리액트 - react query 도입과 suspense error boundary 적용
const test=()=>{
const {data}=useQuery("testQueryKey",fenchFn {suspense:true});
return(
<Suspense fallback={<LoadingPage/>}>
<TargetWidget data={data}>
</Suspense>