[TIL] React에서 페이지 전환 시 blocking 하기(2)

이진호·2024년 1월 3일
1

TIL

목록 보기
57/66
post-custom-banner

어제는 blocking에 대해서 어떤 식으로 구현을 해야 하나에 대해서 찾아봤다면 이번에는 실제로 구현하는 방법에 대해서 실제 코드로 작성을 해봤다.
내가 구현하고자 하는 내용은 SPA에서 페이지 전환이 발생했을 시 그 전환을 막는 것을 구현을 하고 싶다.

window beforeunload

다양한 곳에서 window의 이벤트 중에 beforeunload를 사용하여 페이지 전환이 일어날 시에 막는 로직을 작성할 수 있다고 소개하고 있다.

useBlocker를 이용한 구현

react-router-dom에서 useBlocker라는 것을 제공하고 있는데 이는 페이지 전환 시에 현재 pathname과 다음 pathname이 다를 경우가 인자로 block을 시킬 것인지 아닌지를 결정할 수 있다.

export default function ImportFom() {
	const [value,setValue] = useState('');
  
  	const blocker = useBlocker(
      ({currentLocation,nextLocation}) =>
      	value !== '' &&
      	currentLocation.pathname !== nextLocation.pathname
    );
  
  return (
    <form></form>
    {blocker.state === 'blocked' && (
     	<div>
       <p> Are you sure you want to leave?</p>
       <button onClick={() => blocker.preceed()}> Proceed</button>
       <button onClick={() => blocker.reset()}>Cancel</button>
       </div>
     )}
  )
}

위와 같은 방식으로 사용할 수 있다. useBlocker는 blocker라는 객체를 반환하고 useBlocker에는 함수가 들어가며 currentLocation과 nextLocation, historyAction을 넣을 수 있는 콜백이며 그 외에 아무것도 넣지 않는다면 들어온 값의 boolean 값이 block 할지를 정한다.

이 훅은 다른 비슷한 훅과 다른 점은 바로 브라우저의 confirm을 사용하는 것이 아닌 UI를 커스텀할 수 있다라는 점에 있다.

사용

// Router.jsx
export default function Router() {
  return  <BrowserRouter>
      <Routes>
        <Route path='/' element={<Home />} />
        <Route path='/importWrite' element={<ImportantForm />} />
      </Routes>
    </BrowserRouter>
}

ImportantForm 컴포넌트 form에 value를 하나 채워놓은다음에 Link 컴포넌트를 이용하여 홈페이지로 이동하게 된다면


이런식으로 UI가 밑에 나오게 된다.

트러블 슈팅

사실 저걸 그대로 실행하게 된다면 오류가 하나 발생한다.

data router에서 실행을 해야 한다는 오류인데 data router라는 개념이 없어서 공식문서를 찾아본 결과 react-router-dom에서는 data api를 지원하는 router가 여러 개 있다 그 중에서 하나를 쓰지 않아서 생기는 오류로 내가 현재 사용한 BrowserRotuer는 data api를 지원하지 않는 router 중에서 하나이다.

data api를 지원하는 Router

  • createBrowserRouter
  • createMemoryRouter
  • createHashRouter
  • createStaticRouter

data api를 지원하지 않는 Router

  • <BrowserRouter>
  • <MemoryRouter>
  • <HashRouter>
  • <NativeRouter>
  • <StaticRouter>

결론은 위 data api 중 하나를 사용하면 됐고 그 중에서 createBrowserRouter를 사용하여 해당 문제를 해결하였다.

// Router.jsx
const roter = createBrowserRouter([
  {
	path: '/',
    element: <Home/>
  },
  {
    path: '/importWrite',
    element: <ImportantForm/>
  }
])
export router

//App.tsx
export default function App() {
  return <RouterProvider router={router}/>;
}

위 형식으로 사용하는 것과 useBlocker 함수 구현 내용을 봤는데 내부적으로 Context를 사용하여 data에 대한 흐름을 가지고 있는 것 같다.

profile
dygmm4288
post-custom-banner

0개의 댓글