如何优化React Query中批量Movie组件的Mutation初始化逻辑
优化React Query Mutation重复初始化的方案
针对你提到的每个Movie组件独立初始化mutation导致的资源浪费,以及多页面存在多种电影操作的场景,这里有几个实用的优化方案:
1. 抽离自定义Hook复用Mutation逻辑
把各类电影操作的Mutation封装成独立的自定义Hook,不管是在Movie组件还是其他页面组件里,都能直接调用,既避免重复代码,也统一了操作逻辑。
比如针对「添加至观影清单」的操作,封装一个Hook:
// hooks/useAddToWatchlist.ts import { useMutation, useQueryClient } from '@tanstack/react-query'; import { addToWatchlistApi } from '../api/movies'; export function useAddToWatchlist() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (movie: TMovie) => addToWatchlistApi(movie), // 统一配置回调,比如操作成功后刷新缓存 onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['watchlist'] }); }, }); }
然后在Movie组件里直接用:
// Movie Component import { useAddToWatchlist } from '../hooks/useAddToWatchlist'; function Movie({ movie }: { movie: TMovie }) { const { mutate } = useAddToWatchlist(); return ( <div onClick={() => mutate(movie)}> <img src={movie.posterPath} /> </div> ); }
如果有其他操作(比如标记已看、移除清单),同理封装对应的useMarkAsWatched、useRemoveFromWatchlist等Hook,多页面直接导入即可。
2. 父组件统一初始化Mutation,传递mutate函数
如果只是单页面内的批量组件(比如100个Movie),可以在父组件MoviesPage里只初始化一次Mutation,然后把mutate函数通过props传给每个子组件,这样整个页面只会有一个Mutation实例,大幅减少资源占用。
修改后的代码:
// MoviesPage.tsx import { useMutation, useQueryClient } from '@tanstack/react-query'; import { addToWatchlistApi } from '../api/movies'; import Movie from './Movie'; export default async function MoviesPage() { const movies = await getMovies(); const queryClient = useQueryClient(); const { mutate } = useMutation({ mutationFn: (movie: TMovie) => addToWatchlistApi(movie), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['watchlist'] }); }, }); return ( <div> {movies.map(movie => ( <Movie key={movie.id} movie={movie} handleAddToWatchlist={mutate} /> ))} </div> ); } // Movie Component function Movie({ movie, handleAddToWatchlist }: { movie: TMovie; handleAddToWatchlist: (movie: TMovie) => void }) { return ( <div onClick={() => handleAddToWatchlist(movie)}> <img src={movie.posterPath} /> </div> ); }
如果需要同时支持多种操作,父组件可以初始化多个Mutation,把对应的mutate函数都传给子组件即可。
3. 用工厂函数批量生成操作Hook
如果有大量结构相似的电影操作(比如添加/删除/更新不同类型的清单),可以写一个工厂函数来批量生成对应的useMutation Hook,避免重复编写相似代码:
// hooks/useMovieOperation.ts import { useMutation, useQueryClient } from '@tanstack/react-query'; import { addToWatchlistApi, markAsWatchedApi, removeFromWatchlistApi } from '../api/movies'; type MovieOperationType = 'addToWatchlist' | 'markAsWatched' | 'removeFromWatchlist'; export function createMovieOperationHook(operationType: MovieOperationType) { // 根据操作类型匹配对应的API const getApiFn = () => { switch (operationType) { case 'addToWatchlist': return (movie: TMovie) => addToWatchlistApi(movie); case 'markAsWatched': return (movie: TMovie) => markAsWatchedApi(movie); case 'removeFromWatchlist': return (movieId: number) => removeFromWatchlistApi(movieId); default: throw new Error('Invalid operation type'); } }; // 返回对应的Hook return function useMovieOperation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: getApiFn(), onSuccess: () => { // 根据操作类型刷新对应的缓存 queryClient.invalidateQueries({ queryKey: [operationType] }); }, }); }; } // 生成具体的Hook export const useAddToWatchlist = createMovieOperationHook('addToWatchlist'); export const useMarkAsWatched = createMovieOperationHook('markAsWatched');
之后在组件里的用法和方案1完全一致,新增操作时只需要在工厂函数里加个case就行,维护成本很低。
内容的提问来源于stack exchange,提问作者123 456
相关产品推荐
相关产品推荐

