数据变更

由于 TanStack Router 不存储或缓存数据,它在数据变更中的作用微乎其微,除了对来自外部变更事件的潜在 URL 副作用做出反应。话虽如此,我们已经编制了一份您可能会发现有用的变更相关功能列表以及实现这些功能的库。

寻找并使用支持以下功能的变更工具:

  • 处理和缓存提交状态
  • 提供本地和全局乐观 UI 支持
  • 内置钩子来连接失效(或自动支持它)
  • 同时处理多个进行中的变更
  • 将变更状态组织为全局可访问的资源
  • 提交状态历史记录和垃圾回收

一些建议的库:

Or, even...

与数据获取类似,变更状态不是一刀切的解决方案,因此您需要选择适合您和您团队需求的解决方案。我们建议尝试几种不同的解决方案,看看哪种最适合您。

⚠️ 还在这里?提交状态在持久性方面是一个有趣的话题。您是否永远保留每个变更?您如何知道何时摆脱它?如果用户导航离开屏幕然后返回会怎样?让我们深入了解!

变更后使 TanStack Router 失效

TanStack Router 内置了短期缓存。因此,即使我们在路由匹配卸载后不存储任何数据,如果对存储在 Router 中的数据进行任何变更,当前路由匹配的数据很可能会变得陈旧。

当对加载器数据进行相关变更时,我们可以使用 router.invalidate 强制路由器重新加载所有当前路由匹配:

tsx
const router = useRouter()

const addTodo = async (todo: Todo) => {
  try {
    await api.addTodo()
    router.invalidate()
  } catch {
    //
  }
}
const router = useRouter()

const addTodo = async (todo: Todo) => {
  try {
    await api.addTodo()
    router.invalidate()
  } catch {
    //
  }
}

使所有当前路由匹配失效在后台进行,因此现有数据将继续提供,直到新数据准备就绪,就像您导航到新路由一样。

如果您想等待失效直到所有加载器完成,请将 {sync: true} 传递给 router.invalidate

tsx
const router = useRouter()

const addTodo = async (todo: Todo) => {
  try {
    await api.addTodo()
    await router.invalidate({ sync: true })
  } catch {
    //
  }
}
const router = useRouter()

const addTodo = async (todo: Todo) => {
  try {
    await api.addTodo()
    await router.invalidate({ sync: true })
  } catch {
    //
  }
}

长期变更状态

无论使用哪种变更库,变更通常会创建与其提交相关的状态。虽然大多数变更都是设置后就忘记,但一些变更状态更持久,要么支持乐观 UI,要么向用户提供有关其提交状态的反馈。大多数状态管理器将正确保留此提交状态并公开它,以便可以显示加载旋转器、成功消息、错误消息等 UI 元素。

让我们考虑以下交互:

  • 用户导航到 /posts/123/edit 屏幕以编辑帖子
  • 用户编辑 123 帖子,成功后在编辑器下方看到帖子已更新的成功消息
  • 用户导航到 /posts 屏幕
  • 用户再次导航回 /posts/123/edit 屏幕

如果不通知您的变更管理库有关路由更改的信息,您的提交状态可能仍然存在���当用户返回到上一个屏幕时,仍会看到**"帖子更新成功"**消息。这并不理想。显然,我们的意图不是永远保留这种变更状态,对吧?!

使用变更键

希望并且假设,最简单的方法是您的变更库支持键控机制,允许在键更改时重置变更状态:

tsx
const routeApi = getRouteApi('/room/$roomId/chat')

function ChatRoom() {
  const { roomId } = routeApi.useParams()

  const sendMessageMutation = useCoolMutation({
    fn: sendMessage,
    // Clear the mutation state when the roomId changes
    // including any submission state
    key: ['sendMessage', roomId],
  })

  // Fire off a bunch of messages
  const test = () => {
    sendMessageMutation.mutate({ roomId, message: 'Hello!' })
    sendMessageMutation.mutate({ roomId, message: 'How are you?' })
    sendMessageMutation.mutate({ roomId, message: 'Goodbye!' })
  }

  return (
    <>
      {sendMessageMutation.submissions.map((submission) => {
        return (
          <div>
            <div>{submission.status}</div>
            <div>{submission.message}</div>
          </div>
        )
      })}
    </>
  )
}
const routeApi = getRouteApi('/room/$roomId/chat')

function ChatRoom() {
  const { roomId } = routeApi.useParams()

  const sendMessageMutation = useCoolMutation({
    fn: sendMessage,
    // Clear the mutation state when the roomId changes
    // including any submission state
    key: ['sendMessage', roomId],
  })

  // Fire off a bunch of messages
  const test = () => {
    sendMessageMutation.mutate({ roomId, message: 'Hello!' })
    sendMessageMutation.mutate({ roomId, message: 'How are you?' })
    sendMessageMutation.mutate({ roomId, message: 'Goodbye!' })
  }

  return (
    <>
      {sendMessageMutation.submissions.map((submission) => {
        return (
          <div>
            <div>{submission.status}</div>
            <div>{submission.message}</div>
          </div>
        )
      })}
    </>
  )
}

使用 router.subscribe 方法

对于没有键控机制的库,我们可能需要在用户导航离开屏幕时手动重置变更状态。为了解决这个问���,我们可以使用 TanStack Router 的 invalidatesubscribe 方法在用户不再需要时清除变更状态。

router.subscribe 方法是一个将回调订阅到各种路由器事件的函数。我们在这里特别使用的事件是 onResolved 事件。重要的是要理解,此事件在位置路径_更改(不仅仅是重新加载)并最终解析_时触发。

这是重置旧变更状态的好地方。这是一个例子:

tsx
const router = createRouter()
const coolMutationCache = createCoolMutationCache()

const unsubscribeFn = router.subscribe('onResolved', () => {
  // Reset mutation states when the route changes
  coolMutationCache.clear()
})
const router = createRouter()
const coolMutationCache = createCoolMutationCache()

const unsubscribeFn = router.subscribe('onResolved', () => {
  // Reset mutation states when the route changes
  coolMutationCache.clear()
})