如何使用 updater 和 optimisticUpdater 更新 Relay 中的 store 和 UI?
How to update the store and UI in Relay using updater and optimisticUpdater?
创建记录时,控制台中出现错误:
"Warning: A store update was detected within another store update. Please make sure new store updates aren't being executed within an updater function for a different update"
突变有效,但更新器和 optimisticUpdater 无法将节点添加到存储。
我需要应用程序在创建或删除记录时更新 UI。
我可以使用 Redux 来完成,但我想使用标准的 Relay 工具来完成。
以下是文件:
Environment.js:
import {
Environment,
Network,
QueryResponseCache,
RecordSource,
Store,
} from 'relay-runtime';
const oneMinute = 60 * 1000;
const cache = new QueryResponseCache({ size: 250, ttl: oneMinute });
function fetchQuery(
operation,
variables,
cacheConfig,
) {
const queryID = operation.text;
const isMutation = operation.operationKind === 'mutation';
const isQuery = operation.operationKind === 'query';
const forceFetch = cacheConfig && cacheConfig.force;
const fromCache = cache.get(queryID, variables);
if (
isQuery &&
fromCache !== null &&
!forceFetch
) {
return fromCache;
}
return fetch(`${process.env.REACT_APP_API_PORT}graphql`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: operation.text,
variables,
}),
}).then(response => {
return response.json();
}).then(json => {
if (isQuery && json) {
cache.set(queryID, variables, json);
}
if (isMutation) {
cache.clear();
}
return json;
});
}
const environment = new Environment({
network: Network.create(fetchQuery),
store: new Store(new RecordSource()),
});
export default environment;
CreateHeroMutation.js:
import { commitMutation, graphql } from 'react-relay';
import environment from '../Environment';
import { ConnectionHandler } from 'relay-runtime';
const mutation = graphql`
mutation CreateHeroMutation($input: CreateHeroInput!) {
createHero(input: $input) {
hero {
id
name
date
}
}
}
`;
function sharedUpdater(store, viewer, newEdge) {
const viewerProxy = store.get(viewer.id);
const conn = ConnectionHandler.getConnection(
viewerProxy,
'HeroesList_viewer',
);
ConnectionHandler.insertEdgeAfter(conn, newEdge);
}
let tempID = 0;
function CreateHeroMutation(viewer, name, date) {
commitMutation(
environment,
{
mutation,
variables: {
input: {
name,
date
}
},
updater: (store) => {
const payload = store.getRootField('createHero');
const newEdge = payload.getLinkedRecord('hero');
sharedUpdater(store, viewer, newEdge);
},
optimisticUpdater: (store) => {
const id = 'client:newHero:' + tempID++;
const node = store.create(id, 'Hero');
node.setValue(name, 'name');
node.setValue(id, 'id');
const newEdge = store.create(
'client:newEdge:' + tempID++,
'hero',
);
newEdge.setLinkedRecord(node, 'node');
sharedUpdater(store, viewer, newEdge);
},
onCompleted: (response, errors) => {
console.log('Response received from server.');
},
onError: err => console.error(err),
},
);
}
export default CreateHeroMutation;
此外,整个项目都可以在这里找到:
https://github.com/narzantaria/fullstack-relay-app
谢谢,问候。
在 Relay 中处理这种情况的最简单方法之一是 return 整个项目列表作为有效载荷响应,然后在中继中对其进行突变查询。这样 Relay 将自动用新的 added/removed 节点更新商店。
const CreateHeroMutation = mutationWithClientMutationId({
name: "CreateHero",
inputFields: {
name: { type: new GraphQLNonNull(GraphQLString) },
date: { type: new GraphQLNonNull(GraphQLString) }
},
outputFields: {
hero: {
type: Hero,
resolve: obj => obj
}
},
mutateAndGetPayload: args => {
const hero = new heroModel({
name: args.name,
skills: [],
date: new Date(args.date)
});
return hero
.save()
.then(result => {
console.log(result);
return {
...result._doc,
id: result._doc._id.toString(),
date: new Date(result.date).toISOString(),
// here return a list of heroes
heroes:
connectionFromPromisedArray(heroModel.find({}).limit(100).sort({ _id: -1 })
.then(heroes => {
return heroes.map(hero => {
return {
...hero._doc,
id: hero.id,
date: new Date(hero.date).toLocaleDateString()
};
});
})
};
})
.catch(err => {
console.log(err);
throw err;
});
}
});
然后在前端您可以查询整个列表,Relay 会自动为您更新商店。
mutation CreateHeroMutation($input: CreateHeroInput!) {
createHero(input: $input) {
heroes {
edges {
node {
id
...HeroTpl_hero
}
}
}
}
`;
创建记录时,控制台中出现错误:
"Warning: A store update was detected within another store update. Please make sure new store updates aren't being executed within an updater function for a different update"
突变有效,但更新器和 optimisticUpdater 无法将节点添加到存储。 我需要应用程序在创建或删除记录时更新 UI。
我可以使用 Redux 来完成,但我想使用标准的 Relay 工具来完成。 以下是文件:
Environment.js:
import {
Environment,
Network,
QueryResponseCache,
RecordSource,
Store,
} from 'relay-runtime';
const oneMinute = 60 * 1000;
const cache = new QueryResponseCache({ size: 250, ttl: oneMinute });
function fetchQuery(
operation,
variables,
cacheConfig,
) {
const queryID = operation.text;
const isMutation = operation.operationKind === 'mutation';
const isQuery = operation.operationKind === 'query';
const forceFetch = cacheConfig && cacheConfig.force;
const fromCache = cache.get(queryID, variables);
if (
isQuery &&
fromCache !== null &&
!forceFetch
) {
return fromCache;
}
return fetch(`${process.env.REACT_APP_API_PORT}graphql`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: operation.text,
variables,
}),
}).then(response => {
return response.json();
}).then(json => {
if (isQuery && json) {
cache.set(queryID, variables, json);
}
if (isMutation) {
cache.clear();
}
return json;
});
}
const environment = new Environment({
network: Network.create(fetchQuery),
store: new Store(new RecordSource()),
});
export default environment;
CreateHeroMutation.js:
import { commitMutation, graphql } from 'react-relay';
import environment from '../Environment';
import { ConnectionHandler } from 'relay-runtime';
const mutation = graphql`
mutation CreateHeroMutation($input: CreateHeroInput!) {
createHero(input: $input) {
hero {
id
name
date
}
}
}
`;
function sharedUpdater(store, viewer, newEdge) {
const viewerProxy = store.get(viewer.id);
const conn = ConnectionHandler.getConnection(
viewerProxy,
'HeroesList_viewer',
);
ConnectionHandler.insertEdgeAfter(conn, newEdge);
}
let tempID = 0;
function CreateHeroMutation(viewer, name, date) {
commitMutation(
environment,
{
mutation,
variables: {
input: {
name,
date
}
},
updater: (store) => {
const payload = store.getRootField('createHero');
const newEdge = payload.getLinkedRecord('hero');
sharedUpdater(store, viewer, newEdge);
},
optimisticUpdater: (store) => {
const id = 'client:newHero:' + tempID++;
const node = store.create(id, 'Hero');
node.setValue(name, 'name');
node.setValue(id, 'id');
const newEdge = store.create(
'client:newEdge:' + tempID++,
'hero',
);
newEdge.setLinkedRecord(node, 'node');
sharedUpdater(store, viewer, newEdge);
},
onCompleted: (response, errors) => {
console.log('Response received from server.');
},
onError: err => console.error(err),
},
);
}
export default CreateHeroMutation;
此外,整个项目都可以在这里找到:
https://github.com/narzantaria/fullstack-relay-app
谢谢,问候。
在 Relay 中处理这种情况的最简单方法之一是 return 整个项目列表作为有效载荷响应,然后在中继中对其进行突变查询。这样 Relay 将自动用新的 added/removed 节点更新商店。
const CreateHeroMutation = mutationWithClientMutationId({
name: "CreateHero",
inputFields: {
name: { type: new GraphQLNonNull(GraphQLString) },
date: { type: new GraphQLNonNull(GraphQLString) }
},
outputFields: {
hero: {
type: Hero,
resolve: obj => obj
}
},
mutateAndGetPayload: args => {
const hero = new heroModel({
name: args.name,
skills: [],
date: new Date(args.date)
});
return hero
.save()
.then(result => {
console.log(result);
return {
...result._doc,
id: result._doc._id.toString(),
date: new Date(result.date).toISOString(),
// here return a list of heroes
heroes:
connectionFromPromisedArray(heroModel.find({}).limit(100).sort({ _id: -1 })
.then(heroes => {
return heroes.map(hero => {
return {
...hero._doc,
id: hero.id,
date: new Date(hero.date).toLocaleDateString()
};
});
})
};
})
.catch(err => {
console.log(err);
throw err;
});
}
});
然后在前端您可以查询整个列表,Relay 会自动为您更新商店。
mutation CreateHeroMutation($input: CreateHeroInput!) {
createHero(input: $input) {
heroes {
edges {
node {
id
...HeroTpl_hero
}
}
}
}
`;