[졸업프로젝트] React-Query 적용

krkorklo·2022년 1월 26일
1

졸업프로젝트

목록 보기
5/7

React-Query 적용하기로 한 계기

일단 졸업프로젝트 멘토님이 먼저 제안해주셨다. 제안하시기 전에는 이런 라이브러리가 있는 줄도 몰랐다.
패기있게 한다고 말함. 일 벌이는거 제일 잘함.

근데 찾아보다보니까 장점이 많았다. 가장 큰 장점은

코드 단순화❗️

지금 코드 엄청 중구난방 난리다.
체계적으로 코드를 짜본 적이 없어서 그렇다..ㅎ 생각나는대로 쑤셔넣는다.
쨌든 React-Query는 코드를 확 줄여줄 수 있기 때문에 마음에 들었다.

그래서 일단 도전
😄

React-Query 설치

npm install -dev react-query

npm 명령어로 설치한다.

React-Query 적용

기본 설정

// App.tsx
import { QueryClientProvider, QueryClient } from 'react-query';

const queryClient = new QueryClient();

const App = () => {
  ...

  return (
    <QueryClientProvider client={queryClient}>
      ...
    </QueryClientProvider>
  )  
}

가장 먼저 QueryClientProvider로 react-query를 적용하고자하는 컴포넌트들을 감싸준다.

<Route
  path="/login"
  element={
    isLogin === true ? (
    <Navigate replace to="/" />
    ) : (
      <Login isLogin={isLogin} setIsLogin={() => setIsLogin} />
    )
  }
/>

그리고 redux로 관리했던 isLogin을 App에 선언하고 Login 등 다른 컴포넌트에 전달해서 사용할 수 있게 함

dispatch -> useMutation

// lib/api/user.ts
export const login = async (user: UserType) => {
  return client({
    url: "/auth/login",
    method: "post",
    data: user,
  })
  .then((res) => {
    const access_token = res.data.accessToken;
    const token_exp = res.data.tokenExp;
    cookies.set("access_token", access_token, {
      path: "/",
      expires: new Date(Date.now() + 1000 * 60 * 15),
    });
    return true;
  })
  .catch(() => {
    return false;
  })
};

// modules/user.ts
const [LOGIN, LOGIN_SUCCESS, LOGIN_FAILURE] =
  createRequestActionTypes("user/LOGIN");

export const login = createRequestThunk(LOGIN, userAPI.login);

export default createReducer<UserReducer>(initialState, {
  [LOGIN_SUCCESS]: (state, { payload: login }) => ({
    ...state,
    login,
    error: null,
  }),
  [LOGIN_FAILURE]: (state, { payload: error }) => ({
    ...state,
    login: false,
    error,
  }),
});

// pages/Login.tsx
import { login } from '../modules/user';

const Login = () => {
  ...
  const _handleSubmit = () => {
    dispatch(login(user));
  }
  ...
}

redux를 사용해서 상태 관리를 했던 이전 코드이다.
상태 관리에는 용이했지만 결과값을 dispatch를 호출한 컴포넌트에서는 볼 수 없고 module에서 처리해버려서 결과값 처리에 어려움이 좀 있었다.

그래서 react-query로 변환함
api 파일만 조금 수정하고 그대로 사용했다.

// lib/api/user.ts
export const login = async (user: UserType) => {
  return client({
    url: "/auth/login",
    method: "post",
    data: user,
  });
};

// pages/Login.tsx
const Login = () => {
  const mutationLogin = useMutation((user: UserType) => login(user));
  ...
  const _handleSubmit = () => {
    mutationLogin
      .mutateAsync(user)
      .then((res) => {
        if (res.data.success) {
          setIsLogin(true);
          setToken(res.data.data);
        }
      })
      .catch(() => {
        setErrorMsg("로그인에 실패했습니다");
      });
  };
  ...
}

dispatch -> useQuery

import { load } from '../lib/api/media';
...

const Mypage = () => {
  const { status, data } = useQuery(["loadMedia"], () => load(""));

  const renderByStatus = useCallback(() => {
    switch (status) {
      case "loading":
        return (
          <LoadingContainer>
            <Spin
              tip="Loading..."
              indicator={<LoadingOutlined style={{ fontSize: 50 }} />}
            />
          </LoadingContainer>
        );
      case "error":
        return <ErrorPage />;
      default:
        return (
          <Row gutter={[16, 16]} style={{ marginTop: "30px" }}>
            {data?.data?.map((video: VideoType) => (
              <StyledLink to="/result" key={video.id}>
                <Col
                  id={String(video.id)}
                  style={{ display: "flex", width: 460 }}
                >
                  <img
                    alt={String(video.id)}
                    height="160"
                    src="src"
                  />
                  <VideoTitle>{video.videoName}</VideoTitle>
                </Col>
              </StyledLink>
            ))}
          </Row>
        );
    }
  }, [data?.data, status]);

  return (
    <Container>
      <h2 style={{ fontWeight: "bold" }}>자막이 생성된 미디어</h2>
      {renderByStatus()}
    </Container>
  );
};

export default Mypage;

아직 백엔드가 완성되지 않아서 MyPage에서는 api 호출을 못해보지만 일단 이렇게 바꿔뒀다.

바뀐 디렉토리 구조

src
├─ components
│    └─ Header.tsx
│
├─ interfaces
│    └─ interface.ts
│
├─ lib
│    └─ api
│          ├─ client.ts
│          ├─ media.ts
│          └─ user.ts
│
├─ pages
│    ├─ ErrorPage.tsx
│    ├─ Loading.tsx
│    ├─ Login.tsx
│    ├─ MainPage.tsx
│    ├─ MyPage.tsx
│    ├─ ResultPage.tsx
│    └─ Signup.tsx
│
├─ App.tsx
├─ config.ts
└─ index.tsx

js 파일들을 모두 tsx로 변경하고 redux를 처리하던 modules 폴더를 삭제했다.
modules 내에 코드가 많이 더러웠는데 이제야 조금 깔끔? 해진 것 같아서 마음에 든다.

😉

0개의 댓글