어제는 blocking에 대해서 어떤 식으로 구현을 해야 하나에 대해서 찾아봤다면 이번에는 실제로 구현하는 방법에 대해서 실제 코드로 작성을 해봤다.
내가 구현하고자 하는 내용은 SPA에서 페이지 전환이 발생했을 시 그 전환을 막는 것을 구현을 하고 싶다.
다양한 곳에서 window의 이벤트 중에 beforeunload를 사용하여 페이지 전환이 일어날 시에 막는 로직을 작성할 수 있다고 소개하고 있다.
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 중 하나를 사용하면 됐고 그 중에서 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에 대한 흐름을 가지고 있는 것 같다.