Apollo Mutation组件中Optimistic UI功能失效问题排查
我之前也碰到过类似的情况:React里跑的好好的乐观响应逻辑,到了React Native就没动静。结合你给出的代码和排查点,大概率是这几个地方出了问题,咱们一步步来修复:
1. 别直接修改缓存里的数组!
你在update函数里用data.listApps.items.push(createApp)直接修改原数组,这是个典型的坑——Apollo的缓存依赖不可变数据更新来检测变化,直接push属于修改原对象,React Native环境下Apollo可能识别不到这个变化,自然不会触发组件重新渲染。
把这段代码改成创建新数组的形式:
update={(cache, { data: { createApp } }) => { const data = cache.readQuery({ query: LIST_APPS }); if (typeof createApp.id === "number") { // 生成新的items数组,不碰原数据 const updatedItems = [...data.listApps.items, createApp]; // 完整覆盖缓存数据,保持结构不变 cache.writeQuery({ query: LIST_APPS, data: { ...data, listApps: { ...data.listApps, items: updatedItems } } }); } }}
2. 乐观响应的结构要和服务器返回完全对齐
你提到试过不同的__typename,其实更关键的是:乐观响应里的createApp必须包含服务器返回的所有字段,哪怕是临时值。比如如果服务器返回的App类型还有createdAt这类字段,你没在乐观响应里加,Apollo会因为结构不匹配,拒绝把乐观数据写入缓存。
举个例子,假设服务器返回的App有createdAt,那乐观响应要改成:
createApp({ variables: { id: uuid(), name, link }, optimisticResponse: { __typename: "Mutation", createApp: { __typename: "App", id: negativeRandom(), name, link, createdAt: new Date().toISOString() // 临时生成一个符合格式的值 } } });
你可以去GraphQL Playground里查一下createApp的返回结构,确保乐观响应的字段一个都不少。
3. 检查列表组件的缓存订阅逻辑
要确保你的列表是用<Query>组件包裹的LIST_APPS查询,这样缓存更新时组件才能自动拿到最新数据重新渲染。另外,FlatList的keyExtractor要注意:乐观响应的id是数字,服务器返回的可能是字符串(比如你用的uuid),所以最好把id转成字符串:
keyExtractor={(item) => item.id.toString()}
这样当乐观数据被真实数据替换时,FlatList能正确识别并更新条目。
4. 确认Apollo Client配置没禁用乐观响应
虽然默认是开启的,但保险起见可以检查一下客户端初始化代码,确保mutate的默认选项里乐观响应是打开的:
const client = new ApolloClient({ uri: '你的GraphQL地址', cache: new InMemoryCache(), defaultOptions: { mutate: { optimisticResponse: true, // 确保这个值是true }, }, });
按照这几步改完,应该就能看到乐观响应生效了——点击提交后列表会立刻显示临时数据,等服务器返回后自动替换成真实数据。
内容的提问来源于stack exchange,提问作者deadcoder0904

