用远程状态查询本地状态返回空对象

时间:2018-11-09 00:50:04

标签: reactjs graphql apollo

预期结果: 子组件具有来自远程和本地状态的数据。

实际结果: 子组件将获得一个空对象。

如何重现该问题: 我们的初始查询使用apolloClient.query方法与<Query />组件相反。之所以这样做,是因为我们想利用原始异步JavaScript函数中的数据(React-Router v2 <Route /> getComponents消耗了它的返回值)。当我们使用<Query />进行初始查询时,我没有遇到这个问题。如果我在查询中排除@client指令,则子组件将接收远程数据。如果我要将@client查询下移到... on Content范围内,则会收到这个奇怪的错误,我似乎找不到任何数据。 [Network error]: Error: Missing selection set for object of type haveBeenSelected returned for query field haveBeenSelected

以下代码:

// apolloClient.js
import {
  ApolloClient,
  gql,
  HttpLink,
  InMemoryCache,
  IntrospectionFragmentMatcher,
  ApolloLink,
  withClientState,
  onError
} from './apollo';
import { urls } from './API';
import introspectionQueryResultData from './fragmentTypes.json';

const fragmentMatcher = new IntrospectionFragmentMatcher({
  introspectionQueryResultData
});

const cache = new InMemoryCache({ fragmentMatcher });

const error = onError(({ graphQLErrors, networkError }) => {
  if (graphQLErrors)
    graphQLErrors.map(({ message, locations, path }) =>
      console.log(`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`)
    );
  if (networkError) console.log(`[Network error]: ${networkError}`);
});

const stateLink = withClientState({
  cache,
  defaults: {
    tabs: {
      defaultTabValue: /* some logic here */
      selected: null,
      haveBeenSelected: { __typename: 'haveBeenSelected' },
      __typename: 'Tabs'
    }
  },
  resolvers: {
    Query: {
      tabs(_, __, { cache }) {
        return {};
      }
    },
    Mutation: {
      selectTab: (_, { selected }, { cache }) => {
        const query = gql`
          query {
            tabs @client {
              selected
              haveBeenSelected
            }
          }
        `;
        const { tabs } = cache.readQuery({ query });
        cache.writeData({
          data: {
            tabs: {
              selected,
              haveBeenSelected: {
                [selected]: true,
                ...tabs.haveBeenSelected,
                __typename: 'haveBeenSelected'
              },
              __typename: 'Tabs'
            }
          }
        });
        return null;
      }
    }
  }
});

const link = new HttpLink({
  uri: urls().GRAPHQL
});

const apolloClient = new ApolloClient({
  cache,
  link: ApolloLink.from([error, stateLink, link])
});

apolloClient.onResetStore(stateLink.writeDefaults);

export default apolloClient;

-

// initial query and parent component

const query = gql`
  query Entry($url: String!) {
    entry(url: $url) {
      ... on Page {
        name
        layoutId
      }
      ... on Content {
        id
        name
        displayTitle
        description
      }
    }
  }
`;

const someFunctionThatReturnsParentComponent = async () => {
  const { data = {} } = await apolloClient.query({
    query,
    variables: { url: window.location.pathname }
  });
  const { entry } = data;
  return (
    <ParentComponent {...entry} />
  );
}

-

// some child component that queries for local state

const query = gql`
  query Entry($url: String!) {
    entry(url: $url) {
      tabs @client {
        defaultTabValue
        selected
        haveBeenSelected
      }
      ... on Content {
        description
      }
    }
  }
`;

const SELECT_TAB_MUTATION = gql`
  mutation Entry($selected: String!) {
    selectTab(selected: $selected) @client
  }
`;

  const TabsComponent = props => (
    <Query query={query} variables={{ url: window.location.pathname }}>
      {({
        loading,
        data: {
          tabs: { defaultTab, selected, haveBeenSelected },
          entry: { description }
        }
      }) => (
        <Mutation mutation={SELECT_TAB_MUTATION}>
          {selectTabMutation => (
            <Tabs
              fetching={loading}
              defaultTabValue={defaultTab}
              selectedTabValue={selected}
              haveBeenSelected={haveBeenSelected}
              shouldShowDescriptionTab={!!description}
              selectTab={selected => selectTabMutation({ variables: { selected } })}
              {...props}
            />
          )}
        </Mutation>
      )}
    </Query>
  );

export default TabsComponent;

版本

  System:
    OS: macOS 10.14.1
  Binaries:
    Node: 10.11.0 - /usr/local/bin/node
    npm: 6.4.1 - /usr/local/bin/npm
  Browsers:
    Chrome: 70.0.3538.77
    Safari: 12.0.1
  npmPackages:
    apollo-cache-inmemory: ^1.3.9 => 1.3.9 
    apollo-client: ^2.4.5 => 2.4.5 
    apollo-link: ^1.2.3 => 1.2.3 
    apollo-link-error: ^1.1.1 => 1.1.1 
    apollo-link-http: ^1.5.5 => 1.5.5 
    apollo-link-state: ^0.4.2 => 0.4.2 
    react-apollo: ^2.2.1 => 2.2.4

0 个答案:

没有答案