React - useNavigate, useLocation state null 오류 해결

신혜린·2023년 2월 14일
0

wecode42

목록 보기
24/32
post-custom-banner
  • 2023.02.14(화) 1차 프로젝트 진행 중

useNavigate & useLocation 사용법

// sending page
import { useNavigate } from 'react-router-dom';

const navigate = useNavigate();
const userEmail = 'abcd@naver.com';

const convey = () => {
  navigate('/(이동경로)', {
    state: {
      title: userEmail
    }
  });
};

return (
  <div>
  	<button onClick={convey}>이동</button>
  </div>
  );
  • navigate 함수를 호출해서 두개의 파라미터(이동경로, 전달할 데이터)를 넣어 전달한다.
  • 버튼의 onClick 이벤트 발생 시 데이터를 전달하는 convey() 기능이 발동된다.
// recieving page
import { useLocation } from 'react-router-dom';

const location = useLocation();

const userEmail = location.state.title;
console.log(userEmail) // abcd@naver.com
  • location 함수를 호출해서 navigate함수가 함께 전달한 데이터를 받아온다.
  • 데이터가 객체 형태로 오기 때문에 location.state.title 을 통해 userEmail의 데이터 정보에 접근한다.


🚨 문제상황

상위 페이지가 존재하지 않는 login 페이지에서 생성한 데이터를 각기 다른 password페이지와 newuser 페이지로 전달하는 기능을 구현해야 하는 상황!


🧐 처음 생각해낸 방법

상위 페이지가 존재하지 않는 login 페이지에서 생성한 데이터를 각기 다른 password페이지와 newuser 페이지로 전달하는 기능을 구현하려고 검색하던 중 useNavigateuseLocation을 이용하면 가능하다는 걸 보고 코드를 짜보았다.

// 첫번째 시도
const conveyToPw = () => {
  navigate('/password', { state: { title: userEmail } });
} // '/password' 페이지로 userEmail 데이터를 담아 전달하는 navigate 변수

const conveyToNewuser = () => {
  navigate('/newuser', { state: { title: userEmail } });
} // '/newuser' 페이지로 userEmail 데이터를 담아 전달하는 navigate 변수

return (
  <button
    disabled={error ? false : true}
    onClick={(sendEmail, conveyToPw, conveyToNewuser)} 
    /* onClick 이벤트에 함수 3개가 발동되는 상태 */
    type="submit"
    className="continueBtn"
  >
    계속
  </button>
  );
// 수정 전 onClick 이벤트에 설정되어 있는 {sendEmail} 함수
const sendEmail = () => {
    fetch('http://IP주소:3000/users/lookup', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json;charset=utf-8',
      },
      body: JSON.stringify({ email: userEmail }),
    })
      .then(res => res.json())
      .then(response => {
        if (response.message === 'EMAIL_IS_VERIFIED') {
          navigate('/newuser');
          // '/newuser' 페이지로 navigate만 됨
        } else if (response.message === 'DUPLICATE_EMAIL') {
          navigate('/password');
          // '/password' 페이지로 navigate만 됨
        }
      });
  };

📬 {sendEmail}: sendEmail은 fetch함수가 적혀있고 유저에게 입력받은 이메일 정보를 setState 함수를 통해 userEmail 안에 집어 넣어 백엔드 서버로 전달해주는 함수다.
프론트에서 유저로부터 받은 이메일 정보를 백엔드로 전달했을 때, 백엔드 서버에 이미 있는 유저 데이터인 경우에는 비밀번호를 입력하는 창인 /password 로 넘어가고, 서버에 없는 유저 데이터인 경우엔 회원 정보를 새로 입력해서 가입을 시키는 /newuser 로 넘어가도록 짜여있는 코드다.
📬 button에서 onClick 이벤트가 발생하면 sendEmail이라는 함수가 발동하게 설정되어 있었다.

  • userEmail 데이터를 /password/newuser 페이지로 전달해주는 함수 두개({conveyToPw}, {conveyToNewuser}) 를 만들어서 onClick 이벤트에 한번에 여러개의 함수를 끼워넣으면 버튼을 눌렀을 때 {sendEmail}도 되고, {conveyToPw}도 되고, {conveyToNewuser}도 되지않을까? 하는 생각이 들었음.

-> 이렇게 했더니 버튼을 눌렀을 때 의도한 대로 페이지 이동이 되지 않았다. 이메일 입력창 > 비밀번호 입력창 > 회원가입창 순서대로 이동하는 거 같았음.


  • 이유도 모른 채 끙끙대다가 알게 된 건데 {sendEmail} 속에 있는 fetch함수가 원래는 비동기 처리를 하지만 .then() 때문에 동기 처리를 하게 되기 때문{sendEmail}을 실행해서 userEmail이 서버에 존재하는 데이터인지 아닌지 확인을 하기도 전에 {conveyToPw}{conveyToNewuser}가 전부 다 작동을 해서 뭔가 코드가 꼬인 거 같았다.
    어째서인지 내가 전달한 데이터는 null로 받아와지고..🥲

💡 수정 후

button onClick 속성에 함수를 넣으면 안되겠다, 특정 페이지에 이동할 때에만 그 페이지로 데이터가 전달이 되게끔 코드를 짜야겠다는 생각이 들어서 useLocation 함수를 아예 fetch 코드 안에 집어넣었다.

// 수정 후 onClick 이벤트에 설정되어 있는 {sendEmail} 함수
 const sendEmail = () => {
    fetch('http://-:3000/users/lookup', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json;charset=utf-8',
      },
      body: JSON.stringify({ email: userEmail }),
    })
      .then(res => res.json())
      .then(response => {
        if (response.message === 'EMAIL_IS_VERIFIED') {
          navigate('/newuser', { state: { title: userEmail } }); 
          // 데이터를 navigate을 통해 '/newuser' 페이지로 전달하는 함수 처리를 fetch 안에 집어넣은 형태
        } else if (response.message === 'DUPLICATE_EMAIL') {
          navigate('/password', { state: { title: userEmail } });
        } // 데이터를 navigate을 통해 '/password' 페이지로 전달하는 함수 처리를 fetch 안에 집어넣은 형태
      });
  • 입력받은 이메일 정보가 서버에 존재하지 않는 데이터인 경우에는 /newuser로 이동하면서 userEmail 데이터도 전달
  • 입력받은 이메일 정보가 서버에 존재하는 데이터인 경우에는 /password로 이동하면서 userEmail 데이터도 전달

이렇게 동기적으로 처리되도록 코드를 바꿔줬더니 정상적으로 작동이 됨...!!! ✨


정확한 작동 및 오류 원인에 대해서는 내일 멘토님께 다시 질문해봐야겠다! 그래도 오늘도 이렇게 성장하는 나 자신.. 꽤나 뿌듯한 걸.. 🥸

💡 질문 후 알게 된 사실! useNavigateuseLocation은 직접적으로 페이지를 이동시키는 게 아니라 원하는 정보를 url에 담기게 하는 역할을 한다. 그래서 정보 노출이 url에 적나라하게 될 수 있다는 위험성이 있음. 그렇기 때문에 유저의 개인 정보 같은 것들은 useNavigate으로 처리하는 것보단 백엔드에 보내준 정보를 fetch로 다시 가져와서 사용하는 게 더 안전하다. 정 아니면 url에 꽂히기 전에 Incoding, decoding 처리를 해주던지!

profile
개 발자국 🐾
post-custom-banner

0개의 댓글