React Apollo (GraphQL):如何阻止Query组件在无关状态变更时重发请求
问题原因
父组件pageNo状态更新会触发整个组件重渲染,你直接在Query组件的variables属性里写对象字面量,每次重渲染都会生成全新的对象引用,哪怕里面的a/b/c/d值完全没变,react-apollo也会判定为查询变量发生变更,就会触发重新请求。另外注意你示例代码中状态变量是小写a/b/c/d,Query里传的是大写A/B/C/D,记得对齐变量名避免传空值。
解决方案1:用useMemo缓存查询变量
这是改造成本最低的方案,把查询变量用useMemo包裹,仅当依赖的a/b/c/d变更时才生成新的变量对象:
import { useMemo } from 'react' const MyComponent = () => { const [a, setA] = useState([]); const [b, setB] = useState([]); const [c, setC] = useState([]); const [d, setD] = useState([]); const [pageNo, setPageNo] = useState(0); // 新增:缓存查询变量,仅a/b/c/d变化时才更新 const queryVariables = useMemo(() => ({ filters: { typeA: a, typeB: b, typeC: c, typeD: d, } }), [a, b, c, d]); return ( <div className="wrapper"> <button onClick={()=> setPageNo(pageNo === 1 ? 2 : 1)}> {pageNo === 1 ? 'Next' : 'Previous'} </button> <div className="left"> { pageNo === 1 ? ( // 原有下拉选择逻辑 ) : pageNo === 2 ? ( // 原有下拉选择逻辑 ) } </div> <div className="right"> <Query query={SOME_QUERY} variables={queryVariables} // 替换为缓存的变量对象 /> { ({loading, error, data}) => { if(error) return <div>Error...</div> if(loading) return <div>Loading...</div> return ( // 原有数据渲染逻辑 ) } } </Query> </div> </div> ) }
解决方案2:把查询逻辑抽成独立的Memo组件
如果组件逻辑比较复杂,也可以把Query相关的代码单独抽成组件,用React.memo包裹,仅当传入的过滤器属性变更时才重渲染组件:
import { memo } from 'react' // 独立的查询展示组件,用React.memo做浅比较缓存 const FilteredDataTable = memo(({ a, b, c, d }) => { return ( <Query query={SOME_QUERY} variables={{ filters: { typeA: a, typeB: b, typeC: c, typeD: d, } }} > {({loading, error, data}) => { if(error) return <div>Error...</div> if(loading) return <div>Loading...</div> // 原数据渲染逻辑 return <></> }} </Query> ) }) // 父组件调用 const MyComponent = () => { const [a, setA] = useState([]); const [b, setB] = useState([]); const [c, setC] = useState([]); const [d, setD] = useState([]); const [pageNo, setPageNo] = useState(0); return ( <div className="wrapper"> {/* 原有页码按钮、左侧过滤器逻辑不变 */} <div className="right"> <FilteredDataTable a={a} b={b} c={c} d={d} /> </div> </div> ) }
注意事项
- 更新
a/b/c/d这类引用类型状态时,务必返回新的引用(比如修改数组后返回新数组,不要直接修改原数组再setState),否则useMemo和React.memo的浅比较会检测不到变更,导致查询不更新。 - 不要在
useMemo的依赖数组或者FilteredDataTable的props里加pageNo,否则切换页码还是会触发查询更新。
内容的提问来源于stack exchange,提问作者Hardik Aswal
相关产品推荐
相关产品推荐

