Relay如何强制重取整个节点 刷新所有依赖数据的查询
问题场景
假设我们有如下mutation定义:
const [addCryptoAddress] = useMutation(graphql` mutation useCrypto_AddCryptoWalletAddressMutation( $input: AddCryptoAddressInput! ) { addCryptoAddress(input: $input) { userAccount { cryptoCurrencyAddresses { count edges { node { id address } } } } errors { message } } } `);
该mutation执行成功后,UserAccount下会新增CryptoCurrencyAddresses数据。
代码其他位置存在通过lazyLoadQuery获取上述地址的逻辑,示例如下:
const { visitor } = useLazyLoadQuery<ManualPayoutMachineContextQuery>( graphql` query ManualPayoutMachineContextQuery { visitor { userAccount { cryptoCurrencyAddresses { edges { node { id address canDelete currency isDefault label } } } } } } `, {} );
这是Relay默认store更新逻辑导致的常见问题:mutation返回的结构没有声明查询里用到的额外字段,mutation执行完成写入store后,所有未在mutation中声明的字段会立即变为undefined。比如执行如下遍历代码:
visitor.userAccount?.cryptoCurrencyAddresses.edges .map(({ node }) => { return { address: node.address, canDelete: node.canDelete, currency: node.currency, id: node.id, isDefault: node.isDefault, label: node.label, }; });
得到的返回结果为:
[ { address: '0xc0ffee2547296a45a3885639AC7E10F9d54979', canDelete: undefined, currency: undefined, id: 'WyJDcnlwdG9DdXJyZW5jeUFkZHJlc3MiLDIwMjE3NF0=', isDefault: undefined, label: undefined, } ]
核心诉求:除了在mutation中枚举所有重叠字段的方案外,是否存在方法可以在检测到数据更新时,强制所有依赖该数据的查询自动重新加载?
解决方案
有三种不需要在mutation里补全所有字段的解决方法:
- 方案1:通过mutation的
updater主动标记关联记录过期,触发自动重拉
给useMutation增加updater配置,在Relay写入mutation返回数据的逻辑后,手动把对应关联的记录标记为stale状态。Relay检测到当前挂载的组件依赖了标记为过期的字段时,会自动重新发起对应查询补全全量字段,不会触发全局loading。
示例配置:
这个方案精准度最高,只会触发必要的请求,是日常开发最推荐的方式。const [addCryptoAddress] = useMutation({ mutation: graphql`/* 你原来的mutation定义,不需要加额外字段 */`, updater: (store) => { // 如果你原来没有自定义updater,不需要额外写地址写入逻辑,Relay会默认处理返回数据 const userAccount = store.getRoot() .getLinkedRecord('visitor') ?.getLinkedRecord('userAccount'); if (userAccount) { // 标记地址集合记录过期,只触发依赖该字段的查询重拉 const addressSet = userAccount.getLinkedRecord('cryptoCurrencyAddresses'); addressSet?.invalidateRecord(); } } }) - 方案2:给mutation配置
fetchPolicy: 'network-only',关闭自动store写入
如果mutation返回的数据你本身不需要复用,只是用来通知后端完成新增操作,可以直接给mutation设置网络优先策略,mutation拿到返回结果后不会写入store覆盖原有数据,自然不会出现字段丢失的问题。
注意这个方案下你需要自己在onCompleted回调里判断接口返回的业务错误,因为返回数据不会自动同步到store供其他组件读取。 - 方案3:全局配置
missingFieldHandlers统一处理缺字段场景
如果项目里这类部分字段覆盖的问题很多,不想每个mutation单独加配置,可以在初始化Relay Environment的时候添加missingFieldHandlers配置,当Relay读取store检测到存活查询依赖的字段缺失时,自动触发对应查询的重拉。这个方案维护成本最低,但要做好请求防抖,避免短时间内多个字段缺失触发重复请求。
不要用销毁queryRef再重新执行loadQuery的暴力方案,这种方式会导致所有用到该查询的组件重新触发loading态,用户体验很差。
内容的提问来源于stack exchange,提问作者Gajus
相关产品推荐
相关产品推荐

