web-dev-qa-db-ja.com

next.js、javascript、graphql、react jsでのApolloクライアントの問題

最初にホームページにアクセスしたり、ホームページを更新したりすると、cache.readQueryが機能しないため、リゾルバーでプロファイルを取得できません。

また、APIを無限に呼び出します。

別のページに移動して再びホームページに戻ると、cache.readQueryが機能し、投稿のプロファイルとvoteStatusが正しく取得されます。

誰かが以前にこの問題に直面しましたか? home.tsxは私のプロジェクトのメインページです。

同様に、useQuery(@ apollo/react-hooks)はすべてのページで古いデータを取得します。

経験があれば私を助けてください。

  • home.tsx
    ...
    const GET_POSTS = graphql`
      query posts($accountname: String!, $page: Int, $pathBuilder: any, $postsStatus: String) {
        posts(accountname: $accountname, page: $page, postsStatus: $postsStatus)
          @rest(type: "Post", pathBuilder: $pathBuilder) {
          post_id
          author
          voteStatus(accountname: $accountname) @client
          created_at
        }
      }
    `;
    interface Props {
      author: string;
    }
    const Home: NextPage<Props> = ({ author }) => {
      const { data, fetchMore, loading } = useQuery(GET_POSTS, {
        variables: {
          accountname: author,
          page: 1,
          postsStatus: 'home',
          pathBuilder: () => `posts/?Page=1&Limit=5&domainId=1`,
        },
      });
      const loadMorePosts = () => {
        fetchMore({
          variables: {
            page: page + 1,
            pathBuilder: () => `posts/?Page=${page + 1}&Limit=5&domainId=1`,
          },
          updateQuery: (previousResult, { fetchMoreResult }) => {
            if (!fetchMoreResult) {
              return previousResult;
            }
            setPage(page + 1);
            return Object.assign({}, previousResult, {
              posts: [...previousResult.posts, ...fetchMoreResult.posts],
            });
          },
        });
      };
      return (
        <div></div>
      );
    };
    interface Context extends NextPageContext {
      apolloClient: ApolloClient<NormalizedCacheObject>;
    }
    Home.getInitialProps = async (ctx: Context) => {
      const cookies = nextCookie(ctx);
      const author = cookies[encodeURIComponent(KARMA_AUTHOR)];
      ctx.apolloClient.writeData({
        data: {
          accountName: author,
        },
      });
      return {
        layoutConfig: { layout: labels.DEFAULT },
        meta: {
          title: 'Home',
        },
        author,
      };
    };
    export default withAuthSync(withApollo({ ssr: true })(Home));
  • withApollo.tsx
    import { ApolloClient } from 'apollo-client';
    import { withClientState } from 'apollo-link-state';
    import serverFetch from 'node-fetch';
    import graphql from 'graphql-tag';
    const GET_PROFILE = graphql`
      query Profile($accountname: String!, $domainID: number) {
        profile(accountname: $accountname, domainID: $domainID)
          @rest(type: "Profile", path: "profile/{args.accountname}?domainID={args.domainID}") {
          author
          followers_count
          following_count
        }
      }
    `;
    const cache = new InMemoryCache({
      cacheRedirects: {
        Query: {
          post: (_, { post_id }, { getCacheKey }) => getCacheKey({ __typename: 'Post', post_id }),
        },
      },
      dataIdFromObject: object => {
        switch (object.__typename) {
          case 'Post':
            return getUniquePostId(object.post_id);
          case 'Comment':
            return getUniqueCommentId(object.cmmt_id);
          case 'Profile':
            return object.author;
          default:
            defaultDataIdFromObject(object);
        }
      },
    });
    const resolvers = {
      Post: {
        voteStatus: async ({ post_id }, args, { cache }, info) => {
          const { profile } = cache.readQuery({
            query: GET_PROFILE,
            variables: {
              accountname: args.accountname,
              domainID: 1,
            },
          });
          console.log(profile); // can't make console log because profile is not coming from readQuery
          if (profile) {
            return 1;
          } else {
            return 0;
          }
        },
      },
    };
    const stateLink = withClientState({
      cache,
      resolvers,
    });
    const restLink = new RestLink({
      uri: `${SERVER_URL}/`,
      serverFetch,
    });
    const createApolloClient = (initialState: NormalizedCacheObject, ctx: NextPageContext) => {
      return new ApolloClient({
        ssrMode: true,
        link: ApolloLink.from([stateLink, restLink]),
        cache,
      });
    }
    ...
    export const withApollo = ({ ssr = false } = {}) => (PageComponent: NextPage) => {
      const client = createApolloClient(initialState, ctx);
      ...
      return {
        ...pageProps,
        apolloState: apolloClient.cache.extract(),
        apolloClient: ctx.apolloClient,
      };
    }
11
iGuru1994

_cache.readQuery_ 既存のデータを読み取れません-データを最初に照会する必要があります

おそらく、切り替え中のページの1つがこのデータ(プロファイル)をクエリして、_<Home/>_に戻ったときに使用できるようにします。

解決策-投稿をクエリする前にプロファイルをクエリします。

_const Home: NextPage<Props> = ({ author }) => {
  const { data: dataProfile, error: errorProfile, loading: loadingProfile } = useQuery(GET_PROFILE);
  const { data, fetchMore, loading } = useQuery(GET_POSTS, {
    skip: !dataProfile,
    variables: {
      accountname: author,
      page: 1,
      postsStatus: 'home',
      pathBuilder: () => `posts/?Page=1&Limit=5&domainId=1`,
    },
  });
_

skipオプションは、条件が満たされるまでブロッククエリに使用されます。

ポストは、プロファイルデータを受信した後(およびキャッシュに書き込んだ後)にフェッチされます。このように、ローカルリゾルバー(voteStatus)はcache.readQuery()を使用して必要なデータにアクセスできます。

1
xadm