본문 바로가기
⚛️ React

useParams와 useLocation을 이용한 페이지 이동 (1)

by 슬용이 2022. 6. 5.

들어가기 전에

우리가 Web을 사용하다 보면 브라우저의 url이 페이지마다 바뀌는 것을 볼 수 있다.

리액트에서는 useParams와 useLocation 훅을 활용하여 구현할 수 있는데 이 두가지 훅들이 어떤 기능을 하는지 먼저 알아보자.

 

const params = useParams();
console.log(params);

 

useParams를 console로 확인해보면 객체Object로 id값이 들어있는 것을 볼 수 있다.

이 id값은 Rounter.js에 입력했던 path URL의 id 이다.

 

export default function Router() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Monsters />} />
        <Route path="/monsters/detail/:id" element={<MonsterDetail />} />
      </Routes>
    </BrowserRouter>
  );
}

 

그럼 useLocation을 console로 확인하면 어떤 값이 나올까?

 

const location = useLocation();
console.log(location);

다양한 값들이 나오는데 이 중에 우리가 주로 보아야할 부분은 pathnamesearch 이다.

 

우리는 path parameter를 사용하고 싶을 땐 useParams를 쓸 수 있고,

query parameter를 사용하고 싶을 땐 useLocation을 통한 search 값을 쓸 수 있다.

 

이제 해당 id에 맞는 url을 불러와보자.

params는 id가 key인 객체이니 value값을 얻기 위해서 params.id를 입력하면 되는데,

url에서 인식이 되게 하기 위해서는 템플릿 리터럴을 사용해야 한다.

 

useEffect(() => {
    fetch(`https://jsonplaceholder.typicode.com/users/${params.id}`)
      .then((res) => res.json())
      .then((data) => setMonster(data));
  }, []);

 

그 후 console.log를 통해 해당 값을 잘 받아 오고 있는지 확인해보자.

 

console을 통해 data를 잘 가지고 오는 것은 확인을 하였다.

그러면 이제 해당 정보를 card에 넘겨주도록 하자.

 

const { id, name, email } = monster; // 구조분해 할당을 한 뒤
<Card id={id} name={name} email={email} /> // card 컴포넌트에 전달

그럼 detail에 정보값이 바뀐것을 확인할 수 있다

 

 

그런데 화면을 잘 살펴보면 잠깐 다른 화면이 떴다가 관련 정보가 나오는 것을 볼 수 있다.

이는 useEffect가 컴포넌트가 마운트 된 다음에 실행되는 동작 순서 때문에 생기는 일이다.

 

처음에는 useState({})의 초기값처럼 데이터가 비어 있는 상태인 것이다.

일단 return문을 통해 렌더가 된 후 useEffectfetch함수를 통해 setState로 값을 재설정해준다.

이걸 해결하기 위한 두 가지 방법이 있다.

  1. useEffect의 dependency array 활용
  2. 조건부 렌더링

dependency arrayuseEffect내에 입력하는 부분으로, 해당 배열이 변경될 때만 작동하도록 한다.

다른 말로 표현하면 해당 배열이 변경만 되지 않는다면 보호될 수 있다는 뜻이다.

 

조건부 렌더링은 아래와 같이 적용할 수 있다.

 

{monster.name && (
        <>
          <div className="btnWrapper">
            <button>Back to Monsters List</button>
          </div>
          <Card id={id} name={name} email={email} />
          <div className="btnWrapper">
            <button>Previous</button>
            <button>Next</button>
          </div>
        </>
      )}

 

monster.name이 true일 때 뒷 부분을 렌더하는 조건이다.

단순히 monster && ~~ 으로 하지 않은 이유는 monster 값이 빈 객체 {} 여도 true로 받아들여 렌더가 되기 때문이다!

 

 


 

 

댓글