dukDukz

[React] (useRef 활용) 함수를 특정 페이지에서만 동작하지 않게 하기 본문

웹 개발/React

[React] (useRef 활용) 함수를 특정 페이지에서만 동작하지 않게 하기

헤일리_HJ 2023. 2. 21. 14:56

구현 목표

1) As is

App.js 에서 페이지 이동시마다 loginCheck 함수를 호출시킴

 

2) To be

"페이지를 찾을 수 없음" - NoMatch.jsx 에서 loginCheck 함수를 제외시키고 싶음.

 


useRef를 통해 해결

App.jsx

  const noMatch = useRef();
  
  useEffect(() => {
    if (!noMatch.current) {
      loginCheck(token);
    } else {
      return;
    }
  }, [token, loginCheck]);

 

noMatch 값을 props로 NoMatch 컴포넌트에 넘겨준다.

 

NoMatch.jsx

import React from 'react';
import { useNavigate } from 'react-router-dom';

export default function NoMatch({ noMatch }) {
  const navigate = useNavigate();

  return (
    <div id="no-match" ref={noMatch}>
      <h2>페이지를 찾을 수 없습니다.</h2>
      <button
        className="btn btn-danger"
        onClick={() => {
          navigate(-1);
        }}>
        뒤로가기
      </button>
    </div>
  );
}

 

평소에는 noMatch.current = undefined 가 뜬다.

noMatch.current는 falsy 하므로 if문에 걸려서 loginCheck 가 진행된다. (OK!)

 

"페이지를 찾을 수 없음"- NoMatch 컴포넌트에 접근하게 되면 noMatch ref를 찾을 수 있다.

이때는 noMatch.current 가 truthy 함.

그래서 else 문으로 빠지게 되어 loginCheck를 진행하지 않는다. (OK!)

 

useRef로 변경 전에는...

    const nomatchtext = document.getElementById('no-match');

    if (!nomatchtext) {
      loginCheck(token);
    } else {
      return;
    }

이런식으로 id 값을 가져와서 했는데 당연히 이것도 된다.

근데 React에서는 useRef 사용을 권장하니까 바꿨다.

 


시도 1

1) useState 활용하기 - 실패

더보기

App.jsx

const [noMatch, setNoMatch] = useState(false);

useEffect(() => {
   if (!noMatch) loginCheck(token);
 }, [noMatch, token, loginCheck]);

 

NoMatch.jsx

export default function NoMatch({ noMatch }) {
  useEffect(() => {
    setNoMatch(true);
    
    return function cleanup() {
      setNoMatch(false);
    };
  }, []);

  return (
    <div id="no-match">
      <h2>페이지를 찾을 수 없습니다.</h2>
      <button
        onClick={() => {
          setNoMatch(false);
          navigate(-1);
        }}
       >
        뒤로가기
      </button>
    </div>
  );
}

처음에는 useEffect에서 상태값을 변경하고 뒤로가기 버튼을 눌렀을 때 다시 초기값으로 변경되게 하려고 했는데 이전 페이지로 돌아가도 계속 상태값이 true로 남아있었다.

useEffect 내부에서 cleanup을 안써줘서 그랬던 것. cleanup 함수를 사용하니 값이 초기값으로 변경되는 것을 확인할 수 있었다.

(메가테라 4주차 - 3강 부분...)

 

2) 결과 => 실패

state를 NoMatch 컴포넌트에 넘겨주는데 기존 상태값(false)에서 true로 변경되긴 하는데

App.js 의 if 절에 걸려서 변경되기 전 상태 값이 인식되어 loginCheck 함수로 빠짐.

 


시도 2

1) redux 활용하기 - 실패

state의 문제인가 싶어서 redux 사용으로 변경

더보기

App.jsx

const noMatch = useSelector((state) => state.menu.noMatchStatus);

useEffect(() => {
  if (!noMatch) {
    loginCheck(token);
  }
}, [noMatch, token, loginCheck]);

NoMatch.jsx

function NoMatch() {
  const navigate = useNavigate();
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(setNoMatch({ status: true }));
    
    return function cleanup() {
      dispatch(setNoMatch({ status: false }));
    };
  }, []);
  return (
    <div className="no-match">
      <h2>페이지를 찾을 수 없습니다.</h2>
      <button
        onClick={() => {
          dispatch(setNoMatch({ status: false }));
          navigate(-1);
        }}
      >
        뒤로가기
      </button>
    </div>
  );
}

2) 결과 => 실패

redux에서 SetNoMatch 함수를 가져와서 상태값을 변경한다.

이것 역시 기존 상태값(false)에서 true로 변경되긴 하는데

App.js 의 if 절에 걸려서 변경되기 전 상태 값이 인식되어 loginCheck 함수로 빠짐.