Проблемы клиента Apollo в следующем. js, javascript, graphql, react js - PullRequest
11 голосов
/ 07 мая 2020

Если я сначала посещаю домашнюю страницу или обновляю sh домашнюю страницу, я не могу получить профиль в преобразователе, потому что cache.readQuery не работает.

Так же, как он бесконечно вызывает api.

Если я перейду на другую страницу и снова вернусь на домашнюю страницу, cache.readQuery будет работать и получить профиль и голосование Статус сообщения придет правильно.

Кто-нибудь раньше сталкивался с этой проблемой? home.tsx - это главная страница моего проекта.

Кроме того, useQuery (@ apollo / response-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,
      };
    }

Ответы [ 2 ]

4 голосов
/ 12 мая 2020

Я не работал с этой настройкой и просто предполагаю, что ваше приложение может очищать кеш, поэтому при первоначальной попытке получить этот запрос на домашней странице он терпит неудачу.

Опять же, я могу ошибаться, но согласно этим docs: https://www.apollographql.com/docs/react/caching/cache-interaction/#readquery

Если ваш кеш не содержит всех данных, необходимых для выполнения указанного запроса, readQuery выдает ошибку. Он никогда не пытается получить данные с удаленного сервера.

Похоже, имеет смысл добавить блок try / catch в ваш readQuery

let profile;
try {
  result = cache.readQuery({
    query: GET_PROFILE,
    variables: {
      accountname: args.accountname,
      domainID: 1,
    },
  });
  profile = result.profile;
} catch(err) {
  console.error(err);
  // do something like printing an error in console, or nothing
}
1 голос
/ 17 мая 2020

cache.readQuery не могу прочитать несуществующие данные - сначала нужно запросить данные .

Вероятно, одна из страниц, которую вы переключаете, запрашивает эти данные (профиль), делая их доступными, когда вы go вернетесь к <Home/>.

Решение - запрос профиля перед запросом сообщений: * Параметр 1009 *

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() для доступа к необходимым данным.

...