通常用于创建/更新/删除数据或执行服务器副作用
(1)useMutation
const mutation=useMutation((参数)=>{
向服务器提起修改请求,如
axios.get('/todos', {params:参数});
return 修改后的返回结果
},{可选配置属性})
发起修改请求:
方式一:
mutaion.mutate(参数);
其中:
mutation.mutate函数是一个异步函数,这意味着你不能在事件回调中直接使用它,如果需要event,需要在外部包裹一个函数
const onSubmit = event => {
event.preventDefault()
mutation.mutate(new FormData(event.target))
}
方式二:
Pomise方式:
const res=await mutation.mutateAsync参数);
方式三:
将mutaion存进缓存中,然后通过key调用
queryClient.setMutationDefaults(key,{
mutationFn:提交修改请求并返回结果的方法,
...生命周期方法
})
const mutation = useMutation(key);
mutation.mutate(参数);
方式四:
设置默认提交方法,即为方式三的声明版本
new QueryClient({
defaultOptions: {
mutations:{ 提交的默认配置
mutationFn:设置mutation的默认方法
}
},
})
配置参数:
{
retry:3, 默认情况下不会在出错时提交,除了配置了retry选项
}
其他返回参数:
.status:状态字符串
.isLoading:正在提交,对应status === 'loading'
.isError: 提交遇到一个错误,对应status === 'error'
.isSuccess: 提交成功且数据可用,对应status === 'success'
.isIdle:提交是空闲的或处于新鲜/重置状态,对应status === 'idle'
.error:如果提交处于isError状态,则可以通过error属性获取该错误。
.data:如果提交处于成功状态,则可以通过data属性获取返回的数据
.refetch:用于手动再次查询,在enabled:false时,调用refetch()才会开始查询
.reset(), 清除提交返回的错误信息或数据
(2)useMutation生命周期
方式一:
useMutation(fn,{
onMutate: variables => { variables为给fn传递的参数
发起提交回调
return {name:'jeff'}
},
onError: (error, variables, context) => { context为onMutate返回的内容
错误回调
},
onSuccess: (data, variables, context) => { data为提交请求后返回的数据
成功回调
},
onSettled: (data, error, variables, context) => {
在成功和失败回调之后触发的回调
},
})
方式二:
mutation.mutate({
onSuccess: (data, variables, context) => {
...
},
onError: (error, variables, context) => {
...
},
onSettled: (data, error, variables, context) => {
...
}
})
(3)提交mutaion后,重新设置缓存中查询对应的内容
重新设置缓存中的内部,比重新进行查询更能节省带宽
如:
const mutation = useMutation('edit', {
onSuccess: data => queryClient.setQueryData(key,data),
})
自定义hook:
const useMutateTodo = () => {
const queryClient = useQueryClient()
return useMutation(editTodo, {
onSuccess: (data, variables) => {
queryClient.setQueryData(['todo', { id: variables.id }], data)
},
})
}
(4)乐观数据更新,即错误回滚操作
在提交的生命周期中,先获取到旧值,若发生了错误,则还是将旧值缓存
useMutation(updateTodo, {
onMutate: async newTodo => {
await queryClient.cancelQueries('todos') 停掉所有可能在提交期间会覆盖掉数据的查询
const previousTodos = queryClient.getQueryData('todos') 获取缓存的旧值
return { previousTodos } 将旧值返回给上下文context
},
onError: (err,variables, context) => {
queryClient.setQueryData('todos', context.previousTodos) 若发生错误,则继续缓存旧值
},
onSettled: () => {
queryClient.invalidateQueries('todos') 在提交成功/失败之后都进行重新查询更新状态
},
})
(5)匹配正在提交的mutaion,(当前测试会报错未找到方法)
await queryClient.isMutating() 获取正在提取的mutaion数量
await queryClient.isMutating({
exact:true, 精确匹配mutationKey
fetching:true, 正在抓取的mutation,否则匹配未正在抓取的mutation
predicate:(mutation)=>布尔值, 匹配返回true的mutation
mutationKey:匹配key
})
(6)useMutation的脱水和水化
粗浅理解为:
设备离线时将被暂停的mutation脱水,设备启动时水化后能再次执行被暂停的mutation
即:当后台服务停止,前台被暂停的提交会在服务重启后再次执行
import { dehydrate, hydrate} from 'react-query/hydration'
(1)将mutation存进缓存中
queryClient.setMutationDefaults(key,{
mutationFn:提交修改请求并返回结果的方法,
...生命周期方法
})
(2)提交
const mutation = useMutation(key);
mutation.mutate(参数)
(3)设备离线时,将被暂停的提交去水
const state = dehydrate(queryClient)
(4)设备开启时,将提交水化然后重新提交
hydrate(queryClient, state)
queryClient.resumePausedMutations()
代码示例:
提交脱水和水化:
import React,{useState,useEffect,useCallback,useMemo} from 'react';
import { QueryClient, QueryClientProvider, useQuery,useIsFetching, useInfiniteQuery,useMutation } from 'react-query'
import { ReactQueryDevtools } from 'react-query/devtools'
import { dehydrate, hydrate} from 'react-query/hydration'
import axios from 'axios';
import './query.css';
const queryClient = new QueryClient({
})
const App = () => {
return (
<QueryClientProvider client={queryClient}>
<Example />
<ReactQueryDevtools initialIsOpen={false} position='top-right' />
</QueryClientProvider>
)
}
function Example() {
const [page, setPage] = useState(0);
queryClient.setMutationDefaults('addTodo', {
mutationFn: newTodo => axios.get('/movie', newTodo),
retry: 3,
})
const mutation = useMutation('addTodo')
const state = dehydrate(queryClient)
hydrate(queryClient, state)
queryClient.resumePausedMutations()
console.log(state);
console.log(mutation.data);
return (
<div>
<button
onClick={async () => {
mutation.mutate({ title: 'title' })
}}
>
下一页{page}
</button>
</div>
)
}
export default App