페이지 이동을 했지만 컴포넌트가 마운트 되지 않는다?

페이지 이동을 했지만 컴포넌트가 마운트 되지 않는다?

react-router-dom을 사용하면서 발생한 트러블 슈팅

프로젝트를 처음엔 하나의 페이지 구성으로 계획 했지만 검색에 따라 결과를 다르게 보여주기 위해 페이지 분기 처리가 필요했다. 때문에 react-router-dom을 사용해 페이지를 나누기로 결정했다.

react-router-dom 구성

react-router-dom의 공식문서를 찾아보고 페이지 분기를 나누는 코드를 작성 할 수 있었다.

// main.js
import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import './index.css';
import IndexPage from './page/indexPage';
import DataPage from './page/dataPage';

const router = createBrowserRouter([
  {
    path: '/',
    element: <IndexPage />,
  },
  {
    path: ':id',
    element: <DataPage />,
  },
]);

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>
);

다음과 같이 구성했고 //:id 페이지로 나눴다.

Header, IndexPage, DataPage 구성

Header 컴포넌트를 만들어 <IndexPage /><DataPage />에 넣어주었다.

// src/components/header

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

export default function Header() {
  const inputRef = useRef();

  const navigate = useNavigate();
  const handleSubmit = (e) => {
    e.preventDefault();
    const id = inputRef.current.value;
    navigate(`/${id}`);
  };

  return (
    <header>
      <form onSubmit={handleSubmit}>
        <input ref={inputRef} />
        <button type='submit' />
      </form>
    </header>
  );
}
// src/page/indexPage
// IndexPage

import Header from '../../components/header';

export default function IndexPage() {
  return (
    <>
      <Header />
      <div>index page</div>
    </>
  );
}
// src/page/dataPage
// DataPage
import { useParams } from 'react-router-dom';
import Header from '../../components/header';
import { useEffect, useState } from 'react';

export default function DataPage() {
  const [data, setData] = useState();
  const { id } = useParams();

  const fetchData = (id) => {
    console.log(`${id}의 데이터를 받아왔습니다.`);

    return id;
  };

  useEffect(() => {
    const data = fetchData(id);

    setData(data);
  }, []);

  return (
    <>
      <Header />
      <div>{data} data page</div>
    </>
  );
}

header 컴포넌트는 id를 검색해 dataPage에서 보여주는 역할을 한다.

나는 useNavigate()를 통해 header에서 페이지 이동을 시켜주니 당연히 dataPage가 다시 마운트 되어 데이터를 받아오고 컴포넌트를 그려줄거라고 생각했다.

하지만 그렇지 않고 <DataPage /> 컴포넌트는 다시 그려지기는 했지만 useEffect 안에 있는 데이터는 받아오지 않았다.

처음엔 내가 react-router-dom을 잘못 사용 한 줄 알았다.

그렇게 고민하던중 useEffect 안에 로직이 동작하지 않는다는걸 알았다.

그리고 useEffectdependencyid를 넣어보니 정상적으로 동작하는걸 볼 수 있었다.

내가 생각하는 문제의 이유

reactSingle Page Application이다.

처음에 index.html을 받아온 다음 JavaScript를 통해 동적으로 움직인다.

react-router-dom은 이런 SPAMultiple Page Application 처럼 보이게 움직이도록 보여 주는 것이지 진짜로 MPA로 만들어 주는게 아니다.

그래서 처음 <IndexPage />에서 <DataPage />로 이동 할때는

처음 마운트 되기 때문에 useEffect 안에 로직이 동작하지만

<DataPage />에서 <DataPage />로 이동하게 될때는 useNavigate 때문에 주소는 변경되지만 <DataPage />는 마운트 되는것이 아니라 useEffect 안에 로직은 동작하지 않는다

그러므로, dependencyid를 넣어주면서 id가 변경 될 때마다 useEffect 안에 로직이 동작 되게 만들어 줄 수 있다.

// src/page/dataPage
// DataPage

    ...

  useEffect(() => {
    const data = fetchData(id);

    setData(data);
  }, [id]);

   ...
}

❌ 주의

useNavigate로 페이지를 이동하는것과 주소창에서 페이지를 입력해서 이동하는것은 다르다.

주소창에 입력해서 이동 할 경우 새로운 페이지를 요청해서 받아오기 때문에 위와같은 문제를 겪을수 없습니다.

react가 SPA인것은 알고있었지만 react-router-dom을 사용하면 새로운 페이지로 이동하는것처럼 구현이 되어있고 새롭게 컴포넌트가 구성되는줄 알았지만 전혀 그렇지 않고 한개의 페이지에서 필요한 동작을 만들어줘야하는걸 알았다.