react useEffect 무한루프 문제 해결하기 위한 노력

코덩이·2022년 1월 18일
0
post-thumbnail

💥 react 초보의 삽질이 가득한 글입니다. 진짜 무한루프 문제를 해결하고 싶으신 분은 다른 글을 보시는 걸 추천

🤷‍♂️ 문제발생

react 프로젝트에서
네비게이션을 login 전과 후에 따라 다르게 표현하고 싶었다.
그러던 중 useEffect 무한루프 문제가 발생했다.

당시 코드는 아래와 같다.

useEffect(userCheck, [userC])

// Bookmark.jsx
function Bookmark() {
  const { userC, userCheck } = useUserCheckContext();
  useEffect(userCheck, [userC]);
    return (
    <div className="btn_bookmark_box">
      <NavLink className="btn_bookmark home" to="/" activeClassName="active">
        HOME
      </NavLink>
      <NavLink className="btn_bookmark myroom" to={user_id}>
        MYROOM
      </NavLink>
      {userC ? (
        <NavLink className="btn_bookmark logout" to="/logout">
          Logout
        </NavLink>
      ) : (
        <>
          <NavLink className="btn_bookmark login" to="/login">
            LOGIN
          </NavLink>
          <NavLink className="btn_bookmark join" to="/signup">
            JOIN
          </NavLink>
        </>
      )}
    </div>
  );
}
  • 돌아버릴 것 같은 루프

🔧 해결방안

useEffect(userCheck, [])

useEffect의 두번째 인자를 빈 배열로 지정할 시 새로 랜더링 될 때만 Effect가 발생한다고 하여 변경

  • 검색해보니 대부분 여기서 문제를 해결하고 즐겁게 포스팅을 올리셨다.

그러나 이 경우 로그인 후에 f5를 눌러서 다시 랜더링시켜야 네비게이션에 반영되는 문제가 발생했다. 이때 이상함을 느꼈어야 했는데...

function Bookmark() {
  const { userC, userCheck } = useUserCheckContext();
  useEffect(userCheck, []);

그런데 뭔가 이상하다

userC 가 변경될때마다 랜더링이 되어야하는데 토씨하나 다른 게 없어보인다.

useEffect(userCheck, [userC.userId])

여러값이 함께있는 state인 userC 가.. 토씨 하나까지 같다고해도 뭔가가 다를 수 있으니 특정 속성을 지정해줘 봤다.
네비가 달라지는 조건도 변경해주었다.

function Bookmark() {
  const { userC, userCheck } = useUserCheckContext();
  useEffect(userCheck, [userC.userId]);
    return (
    <div className="btn_bookmark_box">
      <NavLink className="btn_bookmark home" to="/" activeClassName="active">
        HOME
      </NavLink>
      <NavLink className="btn_bookmark myroom" to={user_id}>
        MYROOM
      </NavLink>
      {userC.userId ? (
        <NavLink className="btn_bookmark logout" to="/logout">
          Logout
        </NavLink>
      ) : (
        <>
          <NavLink className="btn_bookmark login" to="/login">
            LOGIN
          </NavLink>
          <NavLink className="btn_bookmark join" to="/signup">
            JOIN
          </NavLink>
        </>
      )}
    </div>
  );
}

다행히 무한루프는 멈추었다!

하지만 F5를 누르지 않으면 반영되지 않는 문제가 재발했다... 어째서지?

userCheck 함수가 실행되지도 않고 userC 값은 초기값

userCheck state인 userC 의 값이 콘솔에 찍어봤을 때 변경되지 않는 것을 확인했다.
리랜더링을 시켜야 함수가 실행되고 제대로 작동하는 현 상황

생각해보니 Effect는 화면이 랜더링 된 후에 실행되는 것

로그인으로 인해 새로 랜더링
-> userCheck 함수로 인해 userC의 초기값 셋팅
-> userC는.. 아무 변화가 없는 게 당연함 !

나는 react 멍청이다

react는 잘못이 없었다.
아무 일도 없는데 왜 변하라고 userC를 닦달했을까?

그럼 어떻게 해야하나

다시 생각해보았다.
어? 로그인하면 로그인페이지에서 다시 홈으로 돌아오며 랜더링이 되는데 그 전에 처리하면 되는 거 아닌가? 왜 여기서 하고 있지?

함수를 사용하는 위치가 틀렸었다

로그인을 담당하는 함수 컴포넌트에 가서 랜더링 되기 전 userCheck() 함수를 실행시켜봤다.

// Login.jsx
function Login({ goBackHome }) {
  const navigate = useNavigate();
  const { user, onChangeHandler } = useUserContext();
  // 테스트중입니다
  const { userCheck } = useUserCheckContext();

  const onLoginEventHandler = async () => {
    const res = await LoginFetch(user);

    if (res.status === 401) {
      window.alert("아이디와 비밀번호를 확인해주세요");
      return;
    }

    window.alert("로그인성공");

    // 테스트중입니다
    // 로그아웃일때도 해줘야하나
    userCheck();
    navigate(`/`);
  };
  

이전에 만지던 랜더링 담당 컴포넌트도 단순히 상태만 불러오는 것으로 수정해줬다.

function Bookmark() {

  const { userC } = useUserCheckContext();

드디어!

드디어 로그인 여부에 따라 네비게이션이 변경 되는 것을 확인했다.
나는 이제 잘 것이다.

+ 추가

useCallback을 사용하면 된다는 제보를 들었는데 한번 시도해봐야겠다

profile
개발공부중

0개의 댓글