SWR:如何高效处理筛选场景?
在SWR中处理多作者书籍请求的缓存优化方案
这个问题确实是SWR使用中很常见的缓存优化场景,核心痛点就是避免重复获取已有数据、最大化复用缓存。我来分享几个实用的解决思路:
1. 拆分请求维度,按单个作者独立缓存
不要把包含多个作者的完整URL作为唯一缓存键,而是把每个作者的请求拆分开,让SWR分别缓存每个作者的书籍数据。这样新增作者时只请求新数据,切换单个作者时直接复用已有缓存:
// 封装单个作者的书籍请求函数 const fetchBooksByAuthor = async (author) => { const res = await fetch(`example.com/books?author[]=${author}`); return res.json(); }; // 针对每个需要的作者单独使用SWR,缓存键用数组标识更清晰 const { data: tolkienBooks } = useSWR(['author', 'tolkien'], () => fetchBooksByAuthor('tolkien')); const { data: shakespeareBooks } = useSWR(['author', 'shakespeare'], () => fetchBooksByAuthor('shakespeare')); // 新增罗琳的书籍时,只新增这一个SWR实例,不会重复请求已有作者的数据 const { data: rowlingBooks } = useSWR(['author', 'rowling'], () => fetchBooksByAuthor('rowling')); // 在客户端合并所有需要的书籍数据 const combinedBooks = [ ...(tolkienBooks || []), ...(shakespeareBooks || []), ...(rowlingBooks || []) ];
这种方式完全贴合SWR的缓存设计理念,每个作者的数据独立存储,复用性极强,后续不管是新增、移除作者,都不会产生冗余请求。
2. 使用mutate手动合并缓存数据
如果业务上必须使用包含多个作者的合并请求URL,可以通过SWR的mutate方法手动更新缓存,避免重新请求全量数据:
// 初始请求的缓存键和数据 const initialAuthors = ['tolkien', 'shakespeare']; const cacheKey = `example.com/books?author[]=${initialAuthors.join('&author[]=')}`; const { data: initialBooks, mutate } = useSWR(cacheKey, fetchBooks); // 新增作者的函数 const addNewAuthor = async (newAuthor) => { // 先单独请求新作者的书籍数据 const newAuthorBooks = await fetch(`example.com/books?author[]=${newAuthor}`).then(res => res.json()); // 手动更新缓存:把新数据合并到现有缓存中,第二个参数false表示不触发重新请求 mutate(prevData => [...(prevData || []), ...newAuthorBooks], false); // 如果之后需要让缓存和服务器同步,可以在合适时机调用mutate()(不带参数)触发重验证 };
当你调用addNewAuthor('rowling')时,只会请求罗琳的书籍,然后直接合并到原缓存里,不会重复拉取托尔金和莎士比亚的数据。
3. 控制重验证选项,避免重复请求已有缓存
当切换回单个作者的请求时,如果该作者的数据已经在缓存中,可以通过SWR的配置选项关闭自动重验证,直接复用缓存:
const { data: tolkienBooks } = useSWR( 'example.com/books?author[]=tolkien', fetchBooks, { revalidateIfStale: false, // 缓存未过期时,不自动重新验证 revalidateOnMount: false, // 组件挂载时不触发重验证,直接用缓存 // 可以搭配cacheTime设置缓存过期时间,比如cacheTime: 3600000(1小时) } );
这个方法适合数据更新频率不高的场景,如果数据可能频繁变动,记得在需要时手动调用mutate()触发重验证,保证数据新鲜度。
4. 自定义缓存存储,实现智能请求合并
如果需要更灵活的缓存策略,可以自定义SWR的缓存存储(比如用Map),在请求前先检查缓存中已有哪些作者的数据,只请求缺失的部分,再合并结果:
// 自定义缓存,按作者名存储书籍数据 const authorCache = new Map(); // 封装合并请求的fetch函数 const fetchCombinedBooks = async (authors) => { // 筛选出缓存中没有的作者 const missingAuthors = authors.filter(author => !authorCache.has(author)); if (missingAuthors.length > 0) { // 只请求缺失作者的数据 const newBooks = await fetch(`example.com/books?author[]=${missingAuthors.join('&author[]=')}`).then(res => res.json()); // 将新数据按作者分类存入缓存 missingAuthors.forEach(author => { authorCache.set(author, newBooks.filter(book => book.author === author)); }); } // 从缓存中合并所有需要的作者数据 return authors.flatMap(author => authorCache.get(author) || []); }; // 使用自定义fetch函数,缓存键用作者数组标识 const { data: combinedBooks } = useSWR(['combined-authors', authors], () => fetchCombinedBooks(authors));
这种方式既保留了合并请求的灵活性,又最大化复用了已有缓存,适合复杂的多维度筛选场景。
内容的提问来源于stack exchange,提问作者Marnix.hoh
相关产品推荐
相关产品推荐

