如何使用 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
        }
     }
   }
 }
`;