GraphQL refetch在TextField清空值时无法稳定触发查询问题
问题根因
清空筛选时查询不触发是三个代码逻辑错误导致的:
- React的state更新是异步批处理的,你在
onChange回调里先调用setState再立刻执行refetch()时,refetch拿到的是当前渲染闭包里的旧状态,不是刚更新的筛选值。当清空操作把值改为空字符串/null时,Apollo Client如果判定本次refetch携带的变量和上一次请求完全一致,会直接返回缓存结果不发起新请求。 - 表单组件混用了受控/非受控模式:所有输入组件都用了
defaultValue属性,没有和state做双向绑定,DOM上的输入值和React里存储的筛选状态可能不一致,清空操作触发的state更新可能和实际输入值不匹配。 - Autocomplete的清空分支写了提前
return,更新responsible状态为null后完全没有触发查询逻辑;同时useQuery的onCompleted回调直接读取外层闭包的data,没有用回调入参返回的最新响应数据,也会导致列表状态更新异常。
修复方案
- 不要在setState后同步手动调用refetch,直接把所有筛选状态作为
useQuery的variables依赖,状态变更后Apollo会自动用最新变量发起查询,从根源上避免闭包旧值问题。 - 把所有输入组件的
defaultValue替换为value属性,做严格的受控绑定,空值统一处理为null,避免空字符串、undefined、null混用导致的变量匹配异常。 - 删除Autocomplete清空逻辑里的提前return,保证清空操作和普通输入逻辑一样只更新对应state,不要在事件回调里零散写refetch调用。
修正后的核心代码
useQuery 部分
const newDate = new Date(); const [date, setDate] = useState(newDate); const [responsible, setResponsible] = useState(null); // 其余筛选状态:task、status、week、no_incident、site 按相同逻辑定义 const { data, loading, error } = useQuery(GET_ALL, { variables: { first: 100, task, status, week, date: date || null, responsible_entity: responsible, no_incident, site }, // 从回调参数取最新响应数据,不要读外层闭包的data onCompleted: (res) => { setItems(res.getAll) }, // 如果不需要缓存拦截,可以加下面配置保证每次变量变更都发网络请求 // fetchPolicy: 'network-only' });
日期筛选TextField
<TextField id="dateFilter" type="date" value={date ? dateToString(date) : ''} variant="outlined" className={classes.textField} onChange={(e) => { // 空输入统一转null,和variables的空值处理对齐 setDate(e.target.value || null); }} />
负责人筛选Autocomplete
<Controller control={control} name="responsible" render={({ field: { onChange, value }, fieldState: { error } }) => ( <Autocomplete id="responsible" options={responsiblesList} value={responsible ? { 'DISTINCT': responsible } : null} getOptionLabel={(option) => option?.DISTINCT || ''} style={{ width: 300 }} className={classes.textField} onInputChange={(event, newInputValue, reason) => { if (reason === 'clear') { setResponsible(null) } else { setResponsible(newInputValue) } }} renderInput={(params) => <TextField {...params} label="select responsible" variant="outlined" />} /> )} />
特殊场景必须手动调用refetch时,一定要把最新的变量作为参数显式传入refetch,比如
refetch({ date: null, responsible: null }),不要依赖闭包中的state值,否则还是会出现旧值导致请求不触发的问题。
内容的提问来源于stack exchange,提问作者Alex Bran
相关产品推荐
相关产品推荐

