Fetcher 컴포넌트를 만든 이유
Suspense 컴포넌트에서 힌트를 얻었고, API 호출 및 상태를 관리하는 로직을 선언형으로 사용하기 위함
function ProductListPage() {
return (
<ProductListFetcher>
<ProductListContainer />
</ProductListFetcher>
);
}
// Fetcher 컴포넌트에서 dispatch와 selector(redux 코드)를 처리
function ProductListFetcher({ children }) {
const dispatch = useDispatch();
const { error } = useSelector(state => state.productList);
useEffect(() => {
// fetchProductList:
// GET /products 요청 후 pending/success/error 액션을 dispatch하는 함수
dispatch(fetchProductList);
}, []);
// redux store에서 데이터를 가져오는 데 문제가 발생하면 렌더링
if (error) {
return <div>문제가 발생했습니다.</div>;
}
// 에러 없이 성공했을 때 렌더링
return children;
}
function ProductListContainer() {
const { data } = useSelector(state => state.productList);
return (
<div>
{data?.map(item => (
<Product title={item.title} rate={item.rate.toFixed(1)} />
))}
</div>
);
}
에러가 발생할 경우 에러 메시지를 보여주는 컴포넌트를 렌더링하는 식으로 에러 관리
React의 Error Boundary 개념을 이용하여 위에서 고민한 내용을 해결할 수 있음
=> 하위 컴포넌트 트리에서 발생한 에러를 잡아서 선언적으로 처리하는 컴포넌트
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
render() {
// 에러 발생 시 fallback UI 렌더링
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
<ErrorBoundary>
<ProductListFetcher>
<ProductListContainer />
</ProductListFetcher>
</ErrorBoundary>;
=> Error Boundary를 이용하여 에러를 선언적으로 해결하고 렌더링(런타임) 중에 발생한 TypeError도 처리