useMutation 不会触发重新渲染 React

问题描述 投票:0回答:1

在 Fullstackopen 课程之后,我正在学习第 6 部分并学习 useQUery / useMutation。

我在接近尾声时陷入困境,因为在我调用 api 并对项目列表进行更改后,我的应用程序不会重新渲染。我在查询参数中尝试了

fetchPolicy:'false'

其他逻辑有效,我必须添加一个项目并更新它,但我可以在开发工具的网络选项卡中看到,当我触发更新时,我收到了“PUT”请求,但后面没有“GET”,所以我猜测应该由“onSuccess”触发的渲染不会触发。

我不明白为什么,我在互联网和这里挖掘了一些用例,但无法弄清楚。

谢谢你们!

这里是App.js

import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query'
import { getAnecdotes, updateAnecdote } from './request'

import AnecdoteForm from './components/AnecdoteForm'
import Notification from './components/Notification'

const App = () => {

  const queryClient = useQueryClient()

  const updateAnecdoteMutation = useMutation({
    mutationFn: updateAnecdote,
    onSuccess: (updatedAnecdote) => {
      queryClient.setQueryData(['anecdotes', updatedAnecdote.id], updatedAnecdote)
    }
  })

  const handleVote = (anecdote) => {
    updateAnecdoteMutation.mutate({ ...anecdote, votes: anecdote.votes + 1 })
  }

  const result = useQuery({
    queryKey: ['anecdotes'],
    queryFn: getAnecdotes,
    refetchOnWindowFocus: false
  })

  if (result.isLoading) {
    return <div>loading data...</div>
  }
  if (result.isError) {
    return <div>Error: {result.error.message}</div>
  }

  const anecdotes = result.data

return (...)

轶事表格.js

import { createAnecdote } from "../request"


const AnecdoteForm = () => {

  const queryClient = useQueryClient()

  const newAnecdoteMutation = useMutation({
    mutationFn: createAnecdote,
    onSuccess: (newAnecdote) => {
      const anecdotes = queryClient.getQueryData(['anecdotes'])
      queryClient.setQueryData(['anecdotes'], anecdotes.concat(newAnecdote))
    }
  })

  const onCreate = (event) => {
    event.preventDefault()
    const content = event.target.anecdote.value
    event.target.anecdote.value = ''
    console.log('new anecdote')
    newAnecdoteMutation.mutate({ content, votes: 0 })
  }
return (...)

request.js


const baseUrl = 'http://localhost:3001/anecdotes'

export const getAnecdotes = () =>
    axios.get(baseUrl).then(res => res.data)

export const createAnecdote = (newAnecdote) => {
    axios.post(baseUrl, newAnecdote).then(res => res.data)
}

export const updateAnecdote = (updatedAnecdote) => {
    axios.put(`${baseUrl}/${updatedAnecdote.id}`, updatedAnecdote).then(res => res.data)
}
reactjs
1个回答
0
投票

问题分析:

1。缓存更新:

React-query 是您用来处理缓存和数据获取的工具。 在使用 updateAnecdoteMutation 修改特定轶事后,您正在使用 queryClient.setQueryData 刷新该特定轶事的缓存数据。 您的列表可能不会重新呈现,因为您只是更新特定轶事的缓存,而不是完整的轶事集合。

2。没有自动重新获取:

您报告网络选项卡上显示“PUT”请求,但其后不显示“GET”请求。 这表明突变后不会发生自动重新获取,很可能是因为 queryClient.setQueryData 不会启动重新获取;相反,它只是更新本地缓存。

决议:

第一个解决方案:重新获取查询并使之无效

要重新获取整个轶事列表,请使用 queryClient.invalidateQueries。这将保证在更新后,组件使用更新的数据重新渲染,并且从服务器接收最新的数据。

要更新轶事,请更新 useMutation 挂钩中的 onSuccess 方法:

const updateAnecdoteMutation = useMutation({
  mutationFn: updateAnecdote,
  onSuccess: () => {
    queryClient.invalidateQueries(['anecdotes'])
  }
})

通过这样做,您可以通过使轶事查询无效并强制其重新加载来确保数据是最新的。

第二种解决方案:手动更新列表缓存

如果您希望手动更新列表缓存而不是重新获取,请确保更新缓存中的完整列表,而不仅仅是特定的轶事。虽然此方法可以防止进一步的网络查询,但它需要手动更新缓存。

要更改完整的轶事列表,请更新 onSuccess 方法:

const updateAnecdoteMutation = useMutation({
  mutationFn: updateAnecdote,
  onSuccess: (updatedAnecdote) => {
    queryClient.setQueryData(['anecdotes'], (oldData) => {
      return oldData.map(anecdote =>
        anecdote.id === updatedAnecdote.id ? updatedAnecdote : anecdote
      )
    })
  }
})

解读:

queryClient.invalidateQueries: 此函数使使用指定查询键的查询无效。之后,每当使用查询键或再次挂载组件时,react-query 都会自动再次检索数据。当您想要确保数据始终处于最新状态而无需手动管理缓存更改时,这会很有帮助。

queryClient.setQueryData: 该技术用于立即刷新缓存。您可以通过包含更新完整列表的功能来确保缓存与您的数据保持同步。这可能会导致您的组件重新加载。

其他提示:

使用乐观更新:如果您想通过在服务器响应之前立即更新 UI 来提供更流畅的用户体验,可以使用乐观更新。这涉及乐观地更新本地状态或缓存,假设服务器请求将成功。这是一个例子:

const updateAnecdoteMutation = useMutation({
  mutationFn: updateAnecdote,
  onMutate: async (updatedAnecdote) => {
    await queryClient.cancelQueries(['anecdotes'])
    const previousAnecdotes = queryClient.getQueryData(['anecdotes'])
    
    queryClient.setQueryData(['anecdotes'], (oldData) =>
      oldData.map(anecdote =>
        anecdote.id === updatedAnecdote.id ? updatedAnecdote : anecdote
      )
    )
    return { previousAnecdotes }
  },
  onError: (err, updatedAnecdote, context) => {
    queryClient.setQueryData(['anecdotes'], context.previousAnecdotes)
  },
  onSettled: () => {
    queryClient.invalidateQueries(['anecdotes'])
  }
})

在此配置中:

  • 可以通过调用onMutate进行乐观更新,即 出现在突变函数之前。
  • 如果突变失败,onError 可以让你返回到 初始状态。
  • 无论突变的结果如何,onSettled 都保证 查询无效。

如果您注意 onSuccess 函数中的缓存更新逻辑,则应该解决更新操作后的重新渲染问题。

© www.soinside.com 2019 - 2024. All rights reserved.