如何用useSWR动态获取更新的roleIds列表数据并避免循环渲染
解决动态多选角色时批量获取权限数据的问题
核心问题分析
你的当前实现存在两个关键问题:
fetcher返回的是Promise数组,SWR会直接将这个数组作为data返回,导致你需要手动处理异步解析,但异步操作完成前privilegeData已经被返回,永远拿不到有效数据。- 每次Hook执行时都会创建新的
privilegeData数组,可能引发不必要的组件重渲染,甚至潜在的无限循环风险。
解决方案
1. 修正Fetcher函数
让fetcher返回单个Promise,内部用Promise.all批量请求并解析所有结果,这样SWR会直接返回已解析的结果数组,无需手动处理Promise:
export const fetcher = (urls: string[]) => Promise.all(urls.map(url => AuthenticatedAPIInstance.get(url).then(res => res.data)))
2. 重构自定义Hook
- 用
useMemo缓存privilegeData,仅当data或roleIds变化时重新计算,避免不必要的重渲染。 - 直接使用SWR返回的已解析
data,无需再处理异步Promise。 - 空数组时跳过请求,减少无效API调用。
import { useSWR } from 'swr'; import { useMemo } from 'react'; export const useMultipleRolePrivileges = (roleIds: (string | number)[]) => { console.log("request made for these roles", roleIds); // 缓存URL数组,仅当roleIds变化时重新生成 const urls = useMemo(() => roleIds.map(roleId => `/role_privileges?role_id=${roleId}`), [roleIds] ); // 空数组时不发起请求 const { data, error } = useSWR(urls.length > 0 ? urls : null, fetcher); // 缓存处理后的数据,同步roleIds的增删变化 const privilegeData = useMemo(() => { if (!data) return []; return data.map((value, index) => ({ value, id: roleIds[index] })); }, [data, roleIds]); const loading = !data && !error; return { loading, privilegeData, error }; };
3. 组件中的优化使用
简化changeHandler逻辑,确保trialIds是React状态变量:
import { useState } from 'react'; const [trialIds, setTrialIds] = useState<(string | number)[]>([]); const { loading: rolePrivilegesLoading, privilegeData: rolePrivileges } = useMultipleRolePrivileges(trialIds); const changeHandler = (e: React.ChangeEvent<HTMLSelectElement>) => { const selectedIds = Array.from(e.selectedOptions).map(opt => opt.value); setTrialIds(selectedIds); };
额外优化点
- 缓存复用:SWR会自动缓存请求结果,当重新添加已选过的角色ID时,直接复用缓存,无需重复请求。
- 类型安全:替换
any为具体类型(如string[]或number[]),提升代码可维护性。 - 错误处理:返回
error状态,方便组件中处理请求失败的场景。
内容的提问来源于stack exchange,提问作者Barioder
相关产品推荐
相关产品推荐

