gpt4 book ai didi

reactjs - Apollo 客户端解析器仅触发一次

转载 作者:行者123 更新时间:2023-12-03 23:50:47 25 4
gpt4 key购买 nike

我目前正在开发一个 react 应用程序,它使用 GraphQL 后端并具有额外的本地状态。我正在使用解析器来解析随时间变化的本地字段,但解析器只触发一次。

如果本地字段发生更改,我尝试使用 cache.readQuery 重新运行查询,但它似乎没有按我预期的那样工作。

export const resolvers = {
Query: {
resolvedDevice: (obj, args, { cache }, info) => {
const data = cache.readQuery({
query: gql`
query {
selectedDevice @client
}
`
});

// do stuff with the data
}
},
Mutation: {
selectDevice: (_, { id }, { cache }) => {
cache.writeData({ data: { selectedDevice: id } });
}
}
};

const query = gql`
query GetResolvedDevice {
resolvedDevice @client
}
`;


在这种情况下,解析器中的“resolvedDevice”只执行一次,即使我通过突变“selectDevice”对缓存进行了突变。我希望通过突变更改本地状态时,解析器也会再次运行,因为缓存正在更改。

这是执行查询的代码:
const ModalContainer = props => {
const { loading, error, data } = useQuery(query);

if (loading || error) {
return null;
}

return (
<Modal
device={data.resolvedDevice}
/>
);
};

在这个组件中,我在 selectedDevice 上运行了一个突变:
export const SELECT_DEVICE = gql`
mutation SelectDevice($id: String!) {
selectDevice(id: $id) @client
}
`;

const DevicesNoGeoContainer = () => {
const [selectDevice] = useMutation(SELECT_DEVICE);

return (
<DevicesNoGeo
onGeoClick={id => {
selectDevice({ variables: { id } });
}}
/>
);
};

最佳答案

当缓存中的值发生变化时,Apollo 知道更新从缓存中提取字段的观察查询。在这种情况下,查询中的字段由本地解析器代替。这意味着 Apollo 没有缓存条目来订阅和响应该特定查询。因此,第一个查询已完成,除非您使用 refetch 显式触发它,否则您将不会获得查询的任何更新。上钩结果。

我们寻求解决此问题的一种方法是在缓存中“持久化”派生字段并在组件查询中使用缓存实现字段。我们可以通过显式观察源字段( selectedDevice )并在处理程序中将派生字段( resolvedDevice )写回缓存来做到这一点(我将继续使用您的字段名称,尽管您可能会考虑重命名它如果你走这条路线,因为它似乎以它的定义方式命名)。

概念验证

export const resolvers = {
Mutation: {
selectDevice: (_, { id }, { cache }) => {
cache.writeData({ data: { selectedDevice: id } });
}
}
};

const client = new ApolloClient({
resolvers
});

const sourceQuery = gql`
query {
selectedDevice @client
}`;

// watch the source field query and write resolvedDevice back to the cache at top-level
client.watchQuery({ query: sourceQuery }).subscribe(value =>
client.writeData({ data: { resolvedDevice: doStuffWithTheData(value.data.selectedDevice) } });

const query = gql`
query GetResolvedDevice {
resolvedDevice @client
}
`;

因为查询中的字段传递给 watchQuery存在于缓存中,每次更改都会调用您的处理程序,并且我们会将派生字段写入缓存作为响应。
因为 resolvedDevice现在存在于缓存中,正在查询它的组件现在将在它更改时获取更新(这将是每当“upteam” selectedDevice 字段更改时)。

现在您可能不想真正将源字段监视查询放在顶层,因为无论您是否使用渲染组件,它都会在您的应用程序启动时运行并监视。如果您对一堆本地状态字段采用这种方法,这将特别糟糕。
我们正在研究一种方法,您可以在其中以声明方式定义派生字段及其实现功能:
export const derivedFields: {
resolvedDevice: {
fulfill: () => client.watchQuery({ query: sourceQuery }).subscribe(value =>
client.writeData({ data: { resolvedDevice: doStuffWithTheData(value.data.selectedDevice),
}
};

然后使用 HOC 让他们参与进来:
import { derivedFields } from './the-file-above';

export const withResolvedField = field => RenderingComponent => {
return class ResolvedFieldWatcher extends Component {
componentDidMount() {
this.subscription = derivedFields[field].fulfill();
}
componentDidUnmount() {
// I don't think this is actually how you unsubscribe, but there's
// some way to do it
this.subscription.cancel();
}
render() {
return (
<RenderingComponent {...this.props } />
);
}
};
};

最后包装你的模态容器:
export default withDerivedField('resolvedDevice')(ModalContainer);

请注意,我在这里的结尾是非常假设的,我只是输入它而不是拉下我们的实际代码。我们又回到了 Apollo 2.5 和 React 2.6,所以你可能不得不适应 hooks 等的方法。不过原理应该是一样的:通过观察缓存中源字段的查询来定义派生字段,然后编写派生字段字段返回缓存。然后,您有一个从源数据到基于派生字段的组件渲染 ui 的 react 级联。

关于reactjs - Apollo 客户端解析器仅触发一次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58202011/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com