Closed3

react-router-dom の Prompt と createBrowserRouter

devalondevalon
import { useCallback, useRef, useEffect } from 'react'
import {
  unstable_useBlocker as useBlocker,
  unstable_BlockerFunction as BlockerFunction,
  Location,
} from 'react-router-dom'

export type BlockerFunctionArgs = Parameters<BlockerFunction>[0]
export type HistoryAction = BlockerFunctionArgs['historyAction']

function usePrompt(
  message: string | BlockerFunction | null | undefined | false
) {
  const blocker = useBlocker(
    useCallback(
      (args: {
        currentLocation: Location
        nextLocation: Location
        historyAction: HistoryAction
      }) => {
        if (typeof message === 'function') {
          return !message(args)
        } else if (typeof message === 'string') {
          return !window.confirm(message)
        } else {
          return false
        }
      },
      [message]
    )
  )
  const prevState = useRef(blocker.state)
  useEffect(() => {
    if (blocker.state === 'blocked') {
      blocker.reset()
    }
    prevState.current = blocker.state
  }, [blocker])
}

export function Prompt({ when, message }: PromptProps) {
  usePrompt(when ? message : false)
  return null
}

interface PromptProps {
  when: boolean
  message: string | BlockerFunction
}
  • useBeforeUnload は function にそもそも対応してないので今回は削除した
devalondevalon
  • 書いてみたがエラーになる。
  • さすがに全部を createBrowserRouter 方式に書き換えるのは無理なので全体を囲むように修正
+ import { createBrowserRouter, RouterProvider } from 'react-router-dom'

+ const router = createBrowserRouter([{ path: '*', Component: App }])

<SomeProviders>
- <BrowserRouter>
-    <App />
- </BrowserRouter>
+ <RouterProvider router={router} />;
</SomeProviders>

動いたので、おしまい。

このスクラップは2023/06/06にクローズされました