HOC 무한 루프

// HOC.js

import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { history } from '../redux/configureStore';
import logger from './Logger';

export default (SpecialComponent, option, adminRoute = null) => {
  /* 
    예)  option: null -> 누구나 출입이 가능한 페이지 (home)
                true -> 로그인한 유저만 출입이 가능한 페이지
                false -> 로그인한 유저는 출입이 불가능한 페이지
  */

  const AuthenticateCheck = (props) => {
    const is_login = useSelector((store) => store.user.is_login);
    const dispatch = useDispatch();

    // 각 상황에 맞게 조건을 잘 분기해줘야한다.
    useEffect(() => {
      if (option != null) {
        if (!is_login && option) {
          sessionStorage.setItem('redirect_url', document.location.pathname);
          history.push('/login');
        } else if (is_login && option === false) {
          history.goBack();
          return;
        }
      }
    }, []);

    return <SpecialComponent />;
  };

  return AuthenticateCheck;
};
// App.js

const exerciseState = useSelector((state) => state.exercise);
// 모든 동작(exercise 모듈이 변경되는 동작)에 반응시켜서 토큰을 갱신해주기 위함.
useEffect(() => {
  if (cookie.get('homt6_is_login')) {
    dispatch(userAction.getUpdatedAccessTokenAPI());
  }, [exerciseState]);

return (
  <>
    <ConnectedRouter history={history}>
      <Switch>
        <Route path="/" exact component={HOC(MainPage, null)} />
        <Route
          path="/mypastroutines"
          exact
          component={HOC(MyPastRoutines, true)}
          />
        <Route path="/login" exact component={HOC(Login, false)} />
        <Route path="/exercise" exact component={HOC(ExerciseListUp, true)} />
        <Route
          path="/exercise/form"
          exact
          component={HOC(FormExercise, truncate)}
          />
        {/* 카카오 로그인 후 랜딩되는 redirect uri */}
        <Route
          path="/oauth/callback/kakao"
          exact
          component={HOC(KakaoLanding, false)}
          />
      </Switch>
    </ConnectedRouter>
    </>
);

위 코드의 플로우를 보면...
App 렌더링 -> HOC 렌더링 -> ExerciseListUp 렌더링 -> Exercise 모듈 재호출 -> App.js의 useEffect[exerciseState] 가 반응함 -> App 재렌더링 -> HOC 재렌더링 -> ExerciseListUp 재렌더링... 무한 루프

const exerciseState = useSelector((state) => state.exercise);
// 모든 동작(exercise 모듈이 변경되는 동작)에 반응시켜서 토큰을 갱신해주기 위함.
useEffect(() => {
  if (cookie.get('homt6_is_login')) {
    dispatch(userAction.getUpdatedAccessTokenAPI());
  }, [exerciseState]);

위 함수를 각 컴포넌트 안으로 이동시켜야 무한루프를 피할 수 있음.

하지만... 토큰을 갱신하는 이유는 토큰이 만료되면 payload를 프론트에서 조회 못하는줄 알았는데 그게 아니었다...
어차피 토큰 갱신은 백엔드에서 해주기로 했으므로 만료된 토큰이라도 갖고만 있으면 유저정보를 빼올수 있음.
결국 exerciseState가 변할때마다 토큰을 갱신해줄 필요까진 없어졌고...

// App.js

useEffect(() => {
  if (cookie.get('homt6_is_login') && cookie.get('homt6_access_token')) {
    dispatch(userAction.checkLogin(cookie.get('homt6_access_token')));
  }
}, []);

위와 같이 첫 렌더링 시에만 checkLogin 함수를 이용해 리덕스에 토큰 payload의 유저 정보를 저장해주면 끝!

profile
빠굥

0개의 댓글