React使用useEffect调用Reddit API次数过多,如何仅在query变更时触发?
问题根因
你当前使用的useEffect没有传入第二个依赖数组参数,这种情况下React会在组件每一次渲染完成后都执行Effect回调,无论哪个状态变更都会触发接口请求,就是你遇到的调用次数过多的问题。
修复方案
给useEffect补充依赖数组,仅将query作为依赖项放入,即可实现只有查询关键词变更时才触发请求的逻辑。同时为了避免内部函数重复创建带来的额外依赖问题,我们可以直接将请求逻辑写在useEffect内部,还可以新增请求中断逻辑避免内存泄漏。
修改后的代码如下:
import React, { useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; function Results() { const query = useSelector(state => state.query); const results = useSelector(state => state.results); const dispatch = useDispatch(); useEffect(() => { // 空query时不发起无效请求 if (!query.trim()) return; // 添加中断控制器,组件卸载/query变更时终止未完成的请求 const controller = new AbortController(); const signal = controller.signal; let postTitles = []; let postSrcs = []; fetch('https://www.reddit.com/r/' + query + '.json', { signal }) .then(response => response.json()) .then(body => { for (let i = 0; i < body.data.children.length; ++i) { if (body.data.children[i].data.post_hint === 'image') { let img_url = body.data.children[i].data.url_overridden_by_dest; postSrcs.push(img_url); } let title = body.data.children[i].data.title; postTitles.push(title); } dispatch({type: "QUERY_RESULTS", payload: postTitles}) }).catch((err) => { // 忽略主动中断请求产生的报错 if (err.name !== 'AbortError') { console.log(err) } }); console.log("use effect triggered") // 清理函数,依赖变化/组件卸载时执行 return () => controller.abort(); }, [query, dispatch]) // 仅query、dispatch变化时触发Effect,dispatch为稳定引用不会频繁变更 return ( <> <h1>Query: {query}</h1> { !results ? <h1>No Results</h1> // 补充key属性避免React渲染警告 : results.map((p, index) => <h6 key={index}> {p} </h6>) } </> ) } export default Results;
补充说明
- 依赖数组中的
dispatch是React Redux提供的稳定引用,不会随着组件渲染发生变化,不会触发Effect重复执行 - 请求中断逻辑属于优化项,如果你不需要可以直接删除,不影响核心功能的正常运行
内容的提问来源于stack exchange,提问作者ziad Sakr
相关产品推荐
相关产品推荐

