
컴포넌트 스트리밍은 페이지 스트리밍보다 더 세밀하게 스트리밍을 설정할 수 있다
기존 loading.tsx 파일 삭제
페이지 컴포넌트 내부에서 비동기 작업중인 코드를 분리
원본
수정본 (비동기 작업 분리)
Suspense로 감싸주기
적용 결과
loading.tsx파일을 이용할 때랑 동일하게 쿼리스트링만 변경하였을 때
로딩상태가 표시되지 않는 문제가 발생한다
하지만 Suspense에서는 key 값을 추가하여 이를 해결할 수 있다
key에 해당하는 값이 변경될 때 마다 로딩 표시가 나타난다
<Suspense key={searchParams.q || ''} fallback={<div>Loading ...</div>}>
적용 결과
ex) 유튜브의 스켈레톤 UI
// 📄 src/components/skeleton/book-item-skeleton.tsx
import style from './book-item-skeleton.module.css';
export default function BookItemSkeleton() {
return (
<div className={style.container}>
<div className={style.cover_img}></div>
<div className={style.info_container}>
<div className={style.title}></div>
<div className={style.subTitle}></div>
<br />
<div className={style.author}></div>
</div>
</div>
);
}
📄 /* src/components/skeleton/book-item-skeleton.module.css */
.container {
display: flex;
gap: 15px;
padding: 20px 10px;
border-bottom: 1px solid rgb(220, 220, 220);
}
.cover_img {
width: 80px;
height: 105px;
background-color: rgb(230, 230, 230);
}
.info_container {
flex: 1;
}
.title,
.subTitle,
.author {
width: 100%;
height: 20px;
background-color: rgb(230, 230, 230);
}
<Suspense fallback={
<>
<BookItemSkeleton />
<BookItemSkeleton />
<BookItemSkeleton />
</>
}
>
...
새로고침 후 결과 확인
* 참고
react-loading-skeleton
자동으로 스켈레톤 UI를 만들어주는 라이브러리
백엔드 서버를 끄고 실습 진행
에러 핸들링 하려는 페이지와 같은 레벨에 error.tsx 파일 생성
// 📄 src/app/(with-searchbar)/error.tsx
'use client';
export default function Error() {
return (
<div>
<h3>오류가 발생했습니다</h3>
</div>
);
}
use client를 통해 클라이언트 컴포넌트로 설정하는 이유는
오류는 서버측에서도, 클라이언트측에서도 발생할 수 있기 때문에
두가지 상황에 대응하기 위함이다
error 를 통해 오류의 정보를 받아올 수 있다
// 📄 src/app/(with-searchbar)/error.tsx
'use client';
import { useEffect } from 'react';
export default function Error({ error }: { error: Error }) {
useEffect(() => {
console.error(error.message);
}, [error]);
return (
<div>
<h3>오류가 발생했습니다</h3>
</div>
);
}
적용 결과
에러가 발생한 페이지를 복구하기 위해 다시 한 번 컴포넌트를 렌더링 시키는 함수
'use client';
import { useEffect } from 'react';
export default function Error({
error,
reset,
}: {
error: Error;
reset: () => void;
}) {
useEffect(() => {
console.error(error.message);
}, [error]);
return (
<div>
<h3>오류가 발생했습니다</h3>
<button onClick={() => reset()}>다시 시도</button>
</div>
);
}
적용 결과
백엔드 서버 실행 후 다시 시도 버튼 클릭
그런데 계속해서 오류가 발생한다
reset이라는 메서드는 클라이언트 측에서만 화면을 다시 렌더링한다
즉, 서버를 다시 실행하지 않기 때문에 데이터가 없으므로 계속해서 오류가 발생한다
페이지를 강제로 새로고침 하여 해결할 수 있다
import { useRouter } from 'next/navigation';
import { startTransition} from 'react';
const router = useRouter();
<button
onClick={() => {
startTransition(() => {
router.refresh();
reset();
});
}}
>
startTransition( )
하나의 콜백 함수를 인수로 전달 받아서 콜백 함수 안에 들어있는 UI를 변경 시키는 작업을 일괄적으로 처리
refresh( )
현재 페이지에 필요한 서버 컴포넌트들을 다시 불러옴
reset( )
에러 상태를 초기화하고 컴포넌트들을 다시 렌더링
적용 결과
