自定义hook中传入useQuery的对象数组调用时为空如何解决?
问题根因
这是典型的闭包陷阱问题,同时属于React Query的用法错误:
- 首次调用
useAddNewEventsData自定义Hook时,newEvents是初始的空数组,useQuery的查询函数() => AddNewEvents(newEvents)会直接捕获这个初始的空数组值存入闭包 - 后续你更新
newEvents状态时,因为queryKey固定写死为'add-new-events-query'没有变化,React Query不会重建查询函数,闭包中存储的还是最初的空数组 - 调用
refetch()时执行的还是旧闭包中的函数,所以拿到的参数永远是空数组
额外说明:POST请求属于数据写入操作,本来就不应该用useQuery实现,useQuery是专门为GET类的数据查询场景设计的,写入操作请使用React Query提供的useMutation。
修复方案
方案1:调整queryKey(临时适配useQuery的写法)
把newEvents加入queryKey数组,只要newEvents更新,queryKey就会变化,React Query会自动重建查询函数,捕获最新的参数值:
export const useAddNewEventsData = (newEvents, onSuccess, onError) => { console.log('before arrow function: ', newEvents); return useQuery(['add-new-events-query', newEvents], () => AddNewEvents(newEvents), { onSuccess: onSuccess, onError: onError, enabled: false, }); };
如果newEvents是引用类型,每次状态更新都会生成新的引用,会触发queryKey变化,符合需求。
方案2:改用useMutation(推荐,符合React Query设计规范)
写入类操作使用useMutation,天然不需要提前绑定参数,调用mutate的时候直接传入最新的参数即可:
首先修改自定义Hook:
// 自定义hook代码 const AddNewEvents = async (newEvents) => { console.log('AddNewEvents fn: ', newEvents); return await axios.post(`${process.env.REACT_APP_API_URL}Event`, newEvents); }; export const useAddNewEventsData = (onSuccess, onError) => { return useMutation(AddNewEvents, { onSuccess: onSuccess, onError: onError, }); };
然后在App.js中使用:
const [newEvents, setNewEvents] = useState([]); const addNewEventsResp = useAddNewEventsData( onSuccessUseAddNewEventsData, onErrorUseAddNewEventsData ); // 填充完newEvents后调用触发请求 const handleSubmit = () => { addNewEventsResp.mutate(newEvents); };
这种方案完全规避了闭包问题,也是React Query官方推荐的增删改操作的实现方式。
内容的提问来源于stack exchange,提问作者Jason Tan
相关产品推荐
相关产品推荐

