React Apollo: невозможно прочитать свойство undefined, когда два компонента отображаются одновременно - PullRequest
0 голосов
/ 12 сентября 2018

Я столкнулся с проблемой с пакетом react-apollo:

  • У меня есть 2 компонента, которые запрашивают один и тот же объект graphql
  • Каждый компонент работает независимо, без ошибок
  • Когда я отрисовываю оба, я получаю ошибку Cannot read property of undefined

Я смог воссоздать ошибку с помощью этого демонстрационного кода.Пожалуйста, найдите его здесь, а также ниже: https://codesandbox.io/s/qvq0y25384

То, что я пробовал без успеха

  • Использование псевдонимов запроса привело к точно такому же поведению
  • Использование fetchPolicy="no-cache" сработало, но это не приемлемо для моего реального случая использования, когда 2 компонента должны использовать кэш для повышения производительности.
  • Использование sharedфрагменты сработали, но это неприемлемо для моего реального случая использования, когда это замедляет оба компонента на каждой странице

Ошибка, которая возникает только при визуализации 2 компонентов

PlanetPhysics.js? [sm]:27 Uncaught TypeError: Cannot read property 'planets' of undefined
    at eval (PlanetPhysics.js? [sm]:27)
    at Query.render (react-apollo.browser.umd.js:479)
    at finishClassComponent (react-dom.development.js:13194)
    at updateClassComponent (react-dom.development.js:13156)
    at beginWork (react-dom.development.js:13825)
    at performUnitOfWork (react-dom.development.js:15864)
    at workLoop (react-dom.development.js:15903)
    at HTMLUnknownElement.callCallback (react-dom.development.js:100)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:138)
    at invokeGuardedCallback (react-dom.development.js:187)
    at replayUnitOfWork (react-dom.development.js:15311)
    at renderRoot (react-dom.development.js:15963)
    at performWorkOnRoot (react-dom.development.js:16561)
    at performWork (react-dom.development.js:16483)
    at performSyncWork (react-dom.development.js:16455)
    at requestWork (react-dom.development.js:16355)
    at scheduleWork$1 (react-dom.development.js:16219)
    at Object.enqueueForceUpdate (react-dom.development.js:11337)
    at Query.Component.forceUpdate (react.development.js:288)
    at Query._this.updateCurrentData (react-apollo.browser.umd.js:371)
    at Object.next (react-apollo.browser.umd.js:342)
    at notifySubscription (Observable.js:126)
    at onNotify (Observable.js:161)
    at SubscriptionObserver.next (Observable.js:215)
    at eval (bundle.umd.js:429)
    at Array.forEach (<anonymous>)
    at Object.next (bundle.umd.js:429)
    at eval (bundle.umd.js:1123)
    at eval (bundle.umd.js:1414)
    at Array.forEach (<anonymous>)
    at eval (bundle.umd.js:1413)
    at Map.forEach (<anonymous>)
    at QueryManager.broadcastQueries (bundle.umd.js:1408)
    at Object.next (bundle.umd.js:1465)
    at notifySubscription (Observable.js:126)
    at onNotify (Observable.js:161)
    at SubscriptionObserver.next (Observable.js:215)
    at eval (bundle.umd.js:62)
    at Array.forEach (<anonymous>)
    at Object.next (bundle.umd.js:62)
    at notifySubscription (Observable.js:126)
    at onNotify (Observable.js:161)
    at SubscriptionObserver.next (Observable.js:215)
    at eval (bundle.umd.js:95)

The above error occurred in the <Query> component:
    in Query (created by PlanetPhysics)
    in PlanetPhysics (created by AppERROR1)
    in ApolloProvider (created by AppERROR1)
    in AppERROR1

Полный код для воссоздания ошибки

index.js

import React from "react";
import ReactDOM from "react-dom";
import { ApolloProvider } from "react-apollo";
import { createClient } from "./client";
import { PlanetPhysics } from "./PlanetPhysics";
import { PlanetDemographics } from "./PlanetDemographics";

const client = createClient({});

/* The error only happens when both components are rendered
 * Uncaught TypeError: Cannot read property 'planets' of undefined
 */

function AppOK1() {
  return (
    <ApolloProvider client={client}>
      <PlanetPhysics />
    </ApolloProvider>
  );
}
function AppOK2() {
  return (
    <ApolloProvider client={client}>
      <PlanetDemographics />
    </ApolloProvider>
  );
}
function AppERROR1() {
  return (
    <ApolloProvider client={client}>
      <PlanetPhysics />
      <PlanetDemographics />
    </ApolloProvider>
  );
}
function AppERROR2() {
  return (
    <ApolloProvider client={client}>
      <PlanetDemographics />
      <PlanetPhysics />
    </ApolloProvider>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<AppOK1 />, rootElement);
// ReactDOM.render(<AppOK2 />, rootElement);
// ReactDOM.render(<AppERROR1 />, rootElement);
// ReactDOM.render(<AppERROR2 />, rootElement);

client.js

import { ApolloClient } from "apollo-client";
import { InMemoryCache } from "apollo-cache-inmemory";
import { HttpLink } from "apollo-link-http";

export function createClient(initialState) {
  return new ApolloClient({
    connectToDevTools: true,
    ssrMode: false,
    link: new HttpLink({
      uri: "https://prevostc-swapi-graphql.herokuapp.com"
    }),
    cache: new InMemoryCache({
      dataIdFromObject: object => {
        const identifier = object.uuid || JSON.stringify(object);
        return object.__typename + "-" + identifier || null;
      }
    }).restore(initialState || {})
  });
}

PlanetPhysics.js

import React from "react";
import gql from "graphql-tag";
import { Query } from "react-apollo";
import { DataBlock } from "./DataBlock";

const PHYSICS_QUERY = gql`
  query {
    allPlanets(first: 4) {
      planets {
        id
        name
        diameter
        rotationPeriod
      }
    }
  }
`;

export function PlanetPhysics() {
  return (
    <Query query={PHYSICS_QUERY}>
      {({ loading, error, data }) => {
        if (loading) return "Loading...";
        if (error) return `Error! ${error.message}`;
        return (
          <div>
            {data.allPlanets.planets.map(p => (
              <DataBlock data={p} title={`Physics: ${p.name}`} key={p.id} />
            ))}
          </div>
        );
      }}
    </Query>
  );
}

PlanetDemographics.js

import React from "react";
import gql from "graphql-tag";
import { Query } from "react-apollo";
import { DataBlock } from "./DataBlock";

const DEMOGRAPHICS_QUERY = gql`
  query {
    allPlanets(first: 4) {
      planets {
        id
        name
        population
      }
    }
  }
`;

export function PlanetDemographics() {
  return (
    <Query query={DEMOGRAPHICS_QUERY}>
      {({ loading, error, data }) => {
        if (loading) return "Loading...";
        if (error) return `Error! ${error.message}`;
        return (
          <div>
            {data.allPlanets.planets.map(p => (
              <DataBlock
                data={p}
                title={`Demographics: ${p.name}`}
                key={p.id}
              />
            ))}
          </div>
        );
      }}
    </Query>
  );
}

DataBlock.js

import React from "react";

export function DataBlock({ title, data }) {
  return (
    <div
      style={{
        border: "1px solid black",
        borderRadius: "5px",
        marginBottom: "10px",
        marginRight: "10px",
        padding: "10px",
        maxWidth: "220px",
        display: "inline-block"
      }}
    >
      <h3 style={{ margin: "5px 5px", textAlign: "center" }}>{title}</h3>
      <table>
        <tbody>
          {Object.keys(data).map(key => (
            <tr key={key}>
              <td style={{ textAlign: "right" }}>{key}: </td>
              <td>{data[key]}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...