Reactjs 中继/图形SQL查询字段“;节点";而不是",;观众;使用this.props.relay.setVariables时

Reactjs 中继/图形SQL查询字段“;节点";而不是",;观众;使用this.props.relay.setVariables时,reactjs,graphql,relayjs,relay,Reactjs,Graphql,Relayjs,Relay,我有一个表,在初始页面加载时获取2个项目。这将正确返回2行。当我检查请求有效负载时,我看到以下信息: {"query":"query CampaignQuery { viewer { id, ...F0 } } fragment F0 on User { _campaigns3iwcB5:campaigns(first:2) { edges { node { id, account_id, start

我有一个表,在初始页面加载时获取2个项目。这将正确返回2行。当我检查请求有效负载时,我看到以下信息:

{"query":"query CampaignQuery {
  viewer {
    id,
    ...F0
  }
}
fragment F0 on User {
  _campaigns3iwcB5:campaigns(first:2) {
    edges {
      node {
        id,
        account_id,
        start_time
      },
      cursor
    },
    pageInfo {
      hasNextPage,
      hasPreviousPage
    }
  },
  id
}","variables":{}}
然后,我有一个按钮,它触发一个函数并设置一个变量,以通过this.props.relay.setVariables返回其他项

然后我得到一个3次重试错误和以下错误:

[{message: "Cannot query field "node" on type "Query".", locations: [{line: 2, column: 3}]}]
当我检查请求负载时,我注意到它正在查询“节点”,而不是像以前那样查询“查看器”

{"query":"query Listdata_ViewerRelayQL($id_0:ID!) {
  node(id:$id_0) {
    ...F0
  }
}
fragment F0 on User {
  _campaignsgsWJ4:campaigns(after:\"CkkKFwoEbmFtZRIPGg1DYW1wYWlnbiBGb3VyEipqEXN+cmVhc29uaW5nLXVzLTAxchULEghDYW1wYWlnbhiAgICA3pCBCgwYACAA\",first:2) {
    edges {
      node {
        id,
        account_id,
        start_time
      },
      cursor
    },
    pageInfo {
      hasNextPage,
      hasPreviousPage
    }
  },
  id
}","variables":{"id_0":"VXNlcjo="}}
这是我的schema.js文件

/* @flow */
/* eslint-disable no-unused-consts, no-use-before-define */
import {
  GraphQLBoolean,
  GraphQLFloat,
  GraphQLID,
  GraphQLInt,
  GraphQLList,
  // GraphQLEnumType,
  GraphQLNonNull,
  GraphQLObjectType,
  GraphQLSchema,
  GraphQLString
} from 'graphql';

// const types = require('graphql').type;
// const GraphQLEnumType = types.GraphQLEnumType;

import {
  connectionArgs,
  connectionDefinitions,
  connectionFromArray,
  fromGlobalId,
  globalIdField,
  mutationWithClientMutationId,
  nodeDefinitions
} from 'graphql-relay';

import {
  User,
  Feature,
  getUser,
  getFeature,
  getFeatures,
  getEventStream,

  Campaign,

  getCampaigns,
  resolveCampaigns,
  campaignById,
} from './database';

// Import loader DataLoader
import Loader from './loader';


/**
 * We get the node interface and field from the Relay library.
 *
 * The first method defines the way we resolve an ID to its object.
 * The second defines the way we resolve an object to its GraphQL type.
 */
const { nodeInterface, nodeField } = nodeDefinitions(
  (globalId) => {
    const { type, id } = fromGlobalId(globalId);
    if (type === 'User') {
      return getUser(id);
    } else if (type === 'Feature') {
      return getFeature(id);
    } else if (type === 'Campaign') {
      return campaignById(id);
    } else {
      return null;
    }
  },
  (obj) => {
    if (obj instanceof User) {
      return userType;
    } else if (obj instanceof Feature) {
      return featureType;
    } else if (obj instanceof Campaign) {
      return campaignType;
    } else {
      return null;
    }
  }
);

/**
 * Define your own types here
 */
const campaignType = new GraphQLObjectType({
  name: 'Campaign',
  description: 'A campaign',
  fields: () => ({
    id: globalIdField('Campaign'),
    account_id: {
      type: GraphQLString,
      description: 'ID of the ad account that owns this campaign',
    },
    adlabels: {
      type: GraphQLString,
      description: 'Ad Labels associated with this campaign',
    },
    buying_type: {
      type: GraphQLString,
      description: 'Buying type, possible values are: AUCTION: default, RESERVED: for reach and frequency ads',
    },
    can_use_spend_cap: {
      type: GraphQLBoolean,
      description: 'Whether the campaign can set the spend cap',
    },
    configured_status: {
      type: GraphQLString, // GraphQLEnumType,
      description: '{ACTIVE, PAUSED, DELETED, ARCHIVED}. If this status is PAUSED, all its active ad sets and ads will be paused and have an effective status CAMPAIGN_PAUSED. Prefer using \'status\' instead of this.',
    },
    created_time: {
      type: GraphQLID,  // this should be a datetime
      description: 'Created Time',
    },
    effective_status: {
      type: GraphQLString, // GraphQLEnumType,
      description: 'The effective status of this campaign. {ACTIVE, PAUSED, DELETED, PENDING_REVIEW, DISAPPROVED, PREAPPROVED, PENDING_BILLING_INFO, CAMPAIGN_PAUSED, ARCHIVED, ADSET_PAUSED}',
    },
    name: {
      type: GraphQLString,
      description: 'Campaign\'s name',
    },
    objective: {
      type: GraphQLString,
      description: 'Campaign\'s objective',
    },
    recommendations: {
      type: GraphQLString, // GraphQLList,
      description: 'If there are recommendations for this campaign, this field includes them. Otherwise, this field will be null.',
    },
    spend_cap: {
      type: GraphQLFloat,
      description: 'A spend cap for the campaign, such that it will not spend more than this cap. Expressed as integer value of the subunit in your currency.',
    },
    start_time: {
      type: GraphQLID,  // this should be a datetime
      description: 'Start Time',
    },
    status: {
      type: GraphQLString,
      description: '{ACTIVE, PAUSED, DELETED, ARCHIVED} If this status is PAUSED, all its active ad sets and ads will be paused and have an effective status CAMPAIGN_PAUSED. The field returns the same value as \'configured_status\', and is the suggested one to use.',
    },
    stop_time: {
      type: GraphQLID,  // this should be a datetime
      description: 'Stop Time',
    },
    updated_time: {
      type: GraphQLID,  // this should be a datetime
      description: 'Updated Time',
    },
  }),
  interfaces: [nodeInterface],
});

const userType = new GraphQLObjectType({
  name: 'User',
  description: 'A person who uses our app',
  fields: () => ({
    id: globalIdField('User'),

    // advertising campaigns
    campaigns: {
      type: campaignConnection,
      description: 'list of campaigns',
      args: connectionArgs,
      resolve: (viewer, args, source, info) => {
        return resolveCampaigns(viewer, args, source, info);
      },
    },

    features: {
      type: featureConnection,
      description: 'Features available to the logged in user',
      args: connectionArgs,
      resolve: (_, args) => connectionFromArray(getFeatures(), args)
    },
    username: {
      type: GraphQLString,
      description: 'Users\'s username'
    },
    website: {
      type: GraphQLString,
      description: 'User\'s website'
    }
  }),
  interfaces: [nodeInterface]
});


const featureType = new GraphQLObjectType({
  name: 'Feature',
  description: 'Feature integrated in our starter kit',
  fields: () => ({
    id: globalIdField('Feature'),
    name: {
      type: GraphQLString,
      description: 'Name of the feature'
    },
    description: {
      type: GraphQLString,
      description: 'Description of the feature'
    },
    url: {
      type: GraphQLString,
      description: 'Url of the feature'
    }
  }),
  interfaces: [nodeInterface]
});

/**
 * Define your own connection types here
 */
const {
  connectionType: featureConnection
} = connectionDefinitions({
  name: 'Feature',
  nodeType: featureType
});

// Campaign list ConnectionType
const {
  connectionType: campaignConnection,
} = connectionDefinitions({
  name: 'Campaign',
  nodeType: campaignType
});


/**
 * This is the type that will be the root of our query,
 * and the entry point into our schema.
 */

// Setup GraphQL RootQuery
const RootQuery = new GraphQLObjectType({
  name: 'Query',
  description: 'Realize Root Query',
  fields: () => ({
    viewer: {
      type: userType,
      resolve: () => '1'
    },
  })
});

/**
 * This is the type that will be the root of our mutations,
 * and the entry point into performing writes in our schema.
 */
const mutationType = new GraphQLObjectType({
  name: 'Mutation',
  fields: () => ({
    // Add your own mutations here
  })
});

/**
 * Finally, we construct our schema (whose starting query type is the query
 * type we defined above) and export it.
 */
export default new GraphQLSchema({
  query: RootQuery
  // Uncomment the following after adding some mutation fields:
  // mutation: mutationType
});
我遇到其他人也有类似的问题,尽管他们没有提到如何解决,但他们说:

问题出在我的定义上。我没有正确加载用户id或标识节点对象。一旦我让它们工作起来,一切都正常

任何帮助都将不胜感激。

TL;博士

您的根查询没有
节点
字段。这就是获取更多项目失败的原因。添加
节点
字段,如下所示:

const RootQuery = new GraphQLObjectType({
  ...
  fields: () => ({
    viewer: {
      ...
    },
    node: nodeField,
  })
});

当我检查请求负载时,我注意到它正在查询“节点”,而不是像以前那样查询“查看器”

{"query":"query Listdata_ViewerRelayQL($id_0:ID!) {
  node(id:$id_0) {
    ...F0
  }
}
fragment F0 on User {
  _campaignsgsWJ4:campaigns(after:\"CkkKFwoEbmFtZRIPGg1DYW1wYWlnbiBGb3VyEipqEXN+cmVhc29uaW5nLXVzLTAxchULEghDYW1wYWlnbhiAgICA3pCBCgwYACAA\",first:2) {
    edges {
      node {
        id,
        account_id,
        start_time
      },
      cursor
    },
    pageInfo {
      hasNextPage,
      hasPreviousPage
    }
  },
  id
}","variables":{"id_0":"VXNlcjo="}}
中继第一次获取对象时,使用常规查询

viewer {
    id,
    ...F0
}
现在,中继知道
查看器的全局ID
。稍后,当需要提取
查看器
的更多数据时,中继使用
节点
根字段直接查询该对象

node(id:$id_0) {
    ...F0
}
请参阅steveluscher的一篇文章,了解节点定义在中继中的工作方式