导航阻止是一种防止导航发生的方式。通常在以下用户尝试导航的情况下使用:
在这些场景中,应向用户显示提示或自定义界面以确认是否要离开当前页面。
导航阻止为底层历史API添加了一层或多层"拦截器"。当存在任何拦截器时,导航将通过以下方式之一暂停:
有两种使用方式:
例如阻止表单存在未保存更改时的导航:
import { useBlocker } from '@tanstack/react-router'
function MyComponent() {
const [formIsDirty, setFormIsDirty] = useState(false)
useBlocker({
shouldBlockFn: () => {
if (!formIsDirty) return false
const shouldLeave = confirm('确定要离开吗?')
return !shouldLeave
},
})
// ...
}
import { useBlocker } from '@tanstack/react-router'
function MyComponent() {
const [formIsDirty, setFormIsDirty] = useState(false)
useBlocker({
shouldBlockFn: () => {
if (!formIsDirty) return false
const shouldLeave = confirm('确定要离开吗?')
return !shouldLeave
},
})
// ...
}
shouldBlockFn提供对current和next位置的类型安全访问:
import { useBlocker } from '@tanstack/react-router'
function MyComponent() {
// 始终阻止从/foo跳转到/bar/123?hello=world
const { proceed, reset, status } = useBlocker({
shouldBlockFn: ({ current, next }) => {
return (
current.routeId === '/foo' &&
next.fullPath === '/bar/$id' &&
next.params.id === 123 &&
next.search.hello === 'world'
)
},
withResolver: true,
})
// ...
}
import { useBlocker } from '@tanstack/react-router'
function MyComponent() {
// 始终阻止从/foo跳转到/bar/123?hello=world
const { proceed, reset, status } = useBlocker({
shouldBlockFn: ({ current, next }) => {
return (
current.routeId === '/foo' &&
next.fullPath === '/bar/$id' &&
next.params.id === 123 &&
next.search.hello === 'world'
)
},
withResolver: true,
})
// ...
}
更多useBlocker钩子信息参见API参考。
除钩子方式外,可使用Block组件实现相同效果:
import { Block } from '@tanstack/react-router'
function MyComponent() {
const [formIsDirty, setFormIsDirty] = useState(false)
return (
<Block
shouldBlockFn={() => {
if (!formIsDirty) return false
const shouldLeave = confirm('确定要离开吗?')
return !shouldLeave
}}
/>
)
// 或
return (
<Block shouldBlockFn={() => !formIsDirty} withResolver>
{({ status, proceed, reset }) => <>{/* ... */}</>}
</Block>
)
}
import { Block } from '@tanstack/react-router'
function MyComponent() {
const [formIsDirty, setFormIsDirty] = useState(false)
return (
<Block
shouldBlockFn={() => {
if (!formIsDirty) return false
const shouldLeave = confirm('确定要离开吗?')
return !shouldLeave
}}
/>
)
// 或
return (
<Block shouldBlockFn={() => !formIsDirty} withResolver>
{({ status, proceed, reset }) => <>{/* ... */}</>}
</Block>
)
}
多数情况下,在钩子中使用window.confirm配合withResolver: false即可明确提示用户。但在需要更贴合应用设计的非侵入式UI时:
注意: 当withResolver为true时,shouldBlockFn的返回值不会直接决定阻止结果。
import { useBlocker } from '@tanstack/react-router'
function MyComponent() {
const [formIsDirty, setFormIsDirty] = useState(false)
const { proceed, reset, status } = useBlocker({
shouldBlockFn: () => formIsDirty,
withResolver: true,
})
// ...
return (
<>
{/* ... */}
{status === 'blocked' && (
<div>
<p>确定要离开吗?</p>
<button onClick={proceed}>是</button>
<button onClick={reset}>否</button>
</div>
)}
</>
}
import { useBlocker } from '@tanstack/react-router'
function MyComponent() {
const [formIsDirty, setFormIsDirty] = useState(false)
const { proceed, reset, status } = useBlocker({
shouldBlockFn: () => formIsDirty,
withResolver: true,
})
// ...
return (
<>
{/* ... */}
{status === 'blocked' && (
<div>
<p>确定要离开吗?</p>
<button onClick={proceed}>是</button>
<button onClick={reset}>否</button>
</div>
)}
</>
}
import { useBlocker } from '@tanstack/react-router'
function MyComponent() {
const [formIsDirty, setFormIsDirty] = useState(false)
useBlocker({
shouldBlockFn: () => {
if (!formIsDirty) {
return false
}
const shouldBlock = new Promise<boolean>((resolve) => {
// 使用自选的模态管理器
modals.open({
title: '确定要离开吗?',
children: (
<SaveBlocker
confirm={() => {
modals.closeAll()
resolve(false)
}}
reject={() => {
modals.closeAll()
resolve(true)
}}
/>
),
onClose: () => resolve(true),
})
})
return shouldBlock
},
})
// ...
}
import { useBlocker } from '@tanstack/react-router'
function MyComponent() {
const [formIsDirty, setFormIsDirty] = useState(false)
useBlocker({
shouldBlockFn: () => {
if (!formIsDirty) {
return false
}
const shouldBlock = new Promise<boolean>((resolve) => {
// 使用自选的模态管理器
modals.open({
title: '确定要离开吗?',
children: (
<SaveBlocker
confirm={() => {
modals.closeAll()
resolve(false)
}}
reject={() => {
modals.closeAll()
resolve(true)
}}
/>
),
onClose: () => resolve(true),
})
})
return shouldBlock
},
})
// ...
}
Block组件通过渲染属性提供相同状态和函数:
import { Block } from '@tanstack/react-router'
function MyComponent() {
const [formIsDirty, setFormIsDirty] = useState(false)
return (
<Block shouldBlockFn={() => formIsDirty} withResolver>
{({ status, proceed, reset }) => (
<>
{/* ... */}
{status === 'blocked' && (
<div>
<p>确定要离开吗?</p>
<button onClick={proceed}>是</button>
<button onClick={reset}>否</button>
</div>
)}
</>
)}
</Block>
)
}
import { Block } from '@tanstack/react-router'
function MyComponent() {
const [formIsDirty, setFormIsDirty] = useState(false)
return (
<Block shouldBlockFn={() => formIsDirty} withResolver>
{({ status, proceed, reset }) => (
<>
{/* ... */}
{status === 'blocked' && (
<div>
<p>确定要离开吗?</p>
<button onClick={proceed}>是</button>
<button onClick={reset}>否</button>
</div>
)}
</>
)}
</Block>
)
}
Your weekly dose of JavaScript news. Delivered every Monday to over 100,000 devs, for free.