Reactjs Apollo客户端解析器只触发一次
我目前正在开发一个react应用程序,它使用GraphQL后端并具有额外的本地状态。我使用解析程序解析随时间变化的本地字段,但解析程序只触发一次 我尝试使用cache.readQuery重新运行查询,以防本地字段发生更改,但它似乎没有像我预期的那样工作Reactjs Apollo客户端解析器只触发一次,reactjs,react-apollo,apollo-client,resolver,Reactjs,React Apollo,Apollo Client,Resolver,我目前正在开发一个react应用程序,它使用GraphQL后端并具有额外的本地状态。我使用解析程序解析随时间变化的本地字段,但解析程序只触发一次 我尝试使用cache.readQuery重新运行查询,以防本地字段发生更改,但它似乎没有像我预期的那样工作 export const resolvers = { Query: { resolvedDevice: (obj, args, { cache }, info) => { const data = cache.rea
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}
/>
);
};
const ModalContainer=props=>{
const{loading,error,data}=useQuery(查询);
如果(加载| |错误){
返回null;
}
返回(
);
};
在这个组件中,我在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 } });
}}
/>
);
};
export const SELECT\u DEVICE=gql`
选择设备($id:String!){
选择设备(id:$id)@client
}
`;
const DevicesNoGeoContainer=()=>{
const[selectDevice]=使用变异(选择设备);
返回(
{
选择设备({变量:{id}});
}}
/>
);
};
Apollo知道当缓存中的值发生变化时,会更新从缓存中提取字段的监视查询。在这种情况下,查询中的字段由本地解析程序实现。这意味着Apollo没有可以订阅和响应特定查询的缓存条目。因此,第一个查询已经完成,除非在钩子结果上使用refetch
显式地触发它,否则您不会得到查询的任何更新
解决这个问题的一种方法是在缓存中“持久化”派生字段,并在组件查询中使用缓存完成的字段。我们可以通过显式地查看源字段(<代码>选择设备),并且在处理程序中,将派生字段(<代码> RealvdEdvs/Cuff> >)写入缓存(我将继续使用您的字段名称,但如果您走这条路线,您可能会考虑重命名它,因为它似乎以其定义的方式命名)。
概念证明
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
现在位于缓存中,因此查询它的组件现在将在每次更改时获得更新(这将在“upsteam”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 } />
);
}
};
};
请注意,我在这里的结尾是非常假设的,我只是把它打出来,而不是把我们的实际代码拉下来。我们也回到了Apollo 2.5和React 2.6上,因此您可能必须调整钩子等的方法。但原则应该是相同的:通过查看缓存中源字段的查询来定义派生字段,然后将派生字段写回缓存。然后根据派生字段将源数据与组件呈现ui进行反应式级联。查询不会自动更新。你能在运行查询/变异的地方发布代码吗?需要明确的是,所涉及的查询都是本地的,或者您正在从后端获取数据?这有帮助吗?抱歉,耽搁了这么久。非常感谢您的回答,非常有帮助。
export default withDerivedField('resolvedDevice')(ModalContainer);