[React] recoil 으로 구현하는 중앙집중식애러 핸들링

도도·2021년 8월 1일
0

기술Velog

목록 보기
16/28

recoil으로 구현하는 중앙집중식애러 핸들링

목적

    1. 애러 코드에 대한 확장성
  • 400,403,404 ... 늘어나는 애러에 대응

    1. 깊은 자식 컴포넌트의 애러
  • 최하단 자식컴포넌트의 애러는 모든 화면의 애러로 표현되어 한다.

    1. 잘못된 url정규식에 대한 애러 및 API에 대한 애러 모두 대응
  • 잘못된 url, 404 애러 ( 혹은 커스텀 페이지 )

  • 올바른 url 이지만, 리소스가 없는 경우 404 애러

  • 올바른 url 이지만, 서버응답에 문제가 생긴경우 400,500 등 애러

구조

  • 최상위 컴포넌트에서 404 등 애러가 발생하면
  • 애러 컴포넌트를 랜더링
  • 아니라면 기존 컴포넌트를 랜더링

시나리오

초기 상태

  • 애러가 없으므로 router에 의해 children 컴포넌트들이 잘 랜더링 된다.
----- toplevel [ 애러없음 -> router 랜더링  ]
-- router/switch/route/
-- children1
-- children2
-- children3
-- children4

깊은 하위 컴포넌트에서 애러발생한 경우

  • 전역 state에서 애러 코드가 감지되고
  • 하위 children 컴포넌트를 랜더링하는 router 컴포넌트 대신에 애러페이지를 랜더링 한다.
----- toplevel [ 애러없음 -> router 랜더링  ]
-- router/switch/route/
-- children1
-- children2
-- children3
-- children4 -> API 404 애러 !

코드

    1. error-state 및 ErrorHandler 정의

ErrorHandler는 마치 미들웨어 같다.

  • 전역상태 중 애러상태가 있다면, 애러페이지 컴포넌트를 랜더링 하고
  • 그렇지 않다면, 정상적으로 Router 컴포넌트를 랜더링 한다.
import React from "react";
import { useHistory } from "react-router-dom";
import { atom, useRecoilState } from "recoil";
import Page404 from "../components/error-page/Page404";
import Page403 from "../components/error-page/Page403";
import Page400 from "../components/error-page/Page400";
import Page500 from "../components/error-page/Page500";

// 애러 state를 가지고 있는 atom
interface IErrorStatus {
  isError: boolean;
  errorCode: "400" | "403" | "404" | "500" | "unknown" | null;
}

const atomErrorStatus = atom<IErrorStatus>({
  key: "ErrorStatus",
  default: {
    isError: false,
    errorCode: null,
  },
});
// atom 애러 state에 의해 error페이지를
// 랜더링하는 render props
const ErrorHandler: React.FC<{}> = ({ children }) => {
  const history = useHistory();
  const [errorStatus, setErrorStatus] = useRecoilState(atomErrorStatus);

  React.useEffect(() => {
    const unlisten = history.listen(() =>
      setErrorStatus(() => ({ errorCode: null, isError: false }))
    );
    return unlisten;
  }, [history, setErrorStatus]);

  const renderContent = () => {
    if (errorStatus.errorCode === "400") return <Page400 />;
    if (errorStatus.errorCode === "403") return <Page403 />;
    if (errorStatus.errorCode === "404") return <Page404 />;
    if (errorStatus.errorCode === "500") return <Page500 />;
    if (errorStatus.isError) return <Page400 />;
    return children;
  };

  return <div>{renderContent()}</div>;
};

export { ErrorHandler, atomErrorStatus };
    1. ErrorHandler 적용

ErrorHandler 컴포넌트 의 children은 애러가 없다면 랜더링이 될 것이다.

import React from "react";
import Test from "components/Test";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import LandingPage from "../pages/common/landing-page";
import { TakersHome } from "../pages/takers/layout/TakerMain";
import { MakersHome } from "../pages/makers/layout/MakerMain";
import { ErrorHandler } from "states/recoil/error-state";
import Page404 from "./error-page/Page404";

const Router = () => {
  return (
    <BrowserRouter>
      <ErrorHandler>
        <Switch>
          <Route path="/" exact component={LandingPage} />
          <Route path="/takers" component={TakersHome} />
          <Route path="/makers" component={MakersHome} />
          <Route path="/test" component={Test} />
          <Route component={Page404} />
          {/* <Redirect from="*" to="/" /> */}
        </Switch>
      </ErrorHandler>
    </BrowserRouter>
  );
};

export default Router;
    1. 애러핸들러 사용

지역 컴포넌트에서 애러가 발생하면 전역상태관리도구인 Recoil에게 이를 알린다.

import React from "react";
import { useRecoilState } from "recoil";
import { atomErrorStatus } from "recoil/error-state";
const StrategySearchC = () => {
  const [errorStatus, setErrorStatus] = useRecoilState(atomErrorStatus);
  setErrorStatus((p) => ({
    isError: true,
    errorCode: "404",
  }));

  return <div>StrategySearch!</div>;
};

export default StrategySearchC;
profile
프론트 주력의 JS 개발자 입니다.! Node.js, React, NestJS 에 관심이 많습니다.

0개의 댓글