React组件使用多个Apollo查询报无法重新声明块级变量错误
问题描述
在单个React组件中定义两个Apollo查询时,初始写法如下:
const { data, loading, error } = useQuery(PlaylistQuery, { variables: { _id: playlistId }, fetchPolicy: "cache-and-network", }); const [loadSong, { called, loading, error, data }] = useLazyQuery(SongQuery, { variables: { _id: song._id, }, });
该写法会直接触发块级作用域变量重复声明的报错:
Cannot redeclare block-scoped variable
可行的优雅解决方案
1. 解构时直接重命名(首选方案)
利用JavaScript原生解构赋值的重命名语法,给两个查询返回的同名字段加上对应业务前缀即可,不需要改动任何Apollo配置,改造成本最低,语义也最清晰。
// 给歌单查询的返回字段加playlist前缀 const { data: playlistData, loading: playlistLoading, error: playlistError } = useQuery(PlaylistQuery, { variables: { _id: playlistId }, fetchPolicy: "cache-and-network", }); // 给歌曲懒查询的返回字段加song前缀,called字段如果不冲突可以不用改 const [loadSong, { called, loading: songLoading, error: songError, data: songData }] = useLazyQuery(SongQuery, { variables: { _id: song._id, }, });
后续使用时直接对应前缀取状态就行,比如歌单加载状态用playlistLoading,歌曲加载状态用songLoading,一眼就能区分字段归属,不会出现状态混淆的问题。
2. 拆分自定义Hook封装查询逻辑(适合复杂场景)
如果组件内查询数量多、逻辑复杂,或者查询逻辑需要在多个组件复用,可以把单个查询的逻辑封装成独立的自定义Hook,从根源上隔离不同查询的作用域,避免同作用域下重名变量的问题,同时也能让组件代码更清爽。
// 单独封装歌单查询Hook function usePlaylistDetail(playlistId) { return useQuery(PlaylistQuery, { variables: { _id: playlistId }, fetchPolicy: "cache-and-network", }); } // 单独封装歌曲懒加载查询Hook function useLoadSong() { return useLazyQuery(SongQuery); } // 业务组件内使用 function MusicPlayer() { // 歌单查询逻辑 const { data: playlistData, loading: playlistLoading, error: playlistError } = usePlaylistDetail(playlistId); // 歌曲查询逻辑,内部变量不会和外层冲突 const [loadSong, { called, loading: songLoading, error: songError, data: songData }] = useLoadSong(); const handleSongClick = (song) => { // 触发查询时再传对应变量即可 loadSong({ variables: { _id: song._id } }); }; // 其余业务逻辑... }
这种写法的好处是查询逻辑和组件视图解耦,后续改查询配置、复用时不需要翻组件代码,维护成本更低。
不推荐为了省事直接把整个查询返回值存为单个对象(比如
const playlistQuery = useQuery(...),使用时取playlistQuery.data),这种写法写起来冗余,字段语义也不如明确重命名清晰。
内容的提问来源于stack exchange,提问作者Bowis
相关产品推荐
相关产品推荐

