Вы должны добавить table
реквизит к каждому leg
.Согласно документации graphql.org вы должны думать о графиках:
С GraphQL вы моделируете свой бизнес-домен в виде графа, определяя схему;в своей схеме вы определяете различные типы узлов и то, как они соединяются / связаны друг с другом.
В вашей модели таблицы и ветви являются узлами в графе вашей бизнес-модели.Когда вы добавляете опору таблицы к каждому участку, вы создаете новое ребро на этом графике, которое может пройти ваш код на стороне клиента для получения соответствующих данных.
Редактировать после уточнения:
Вы можете использовать writeFragment
и получить полный контроль над кешем Apollo.Когда запрос на заполнение кеша выполнен, вычислите обратную зависимость и запишите ее в кеш следующим образом:
fetchTables = async () => {
const client = this.props.client
const result = await client.query({
query: ALL_TABLES_QUERY,
variables: {}
})
// compute the reverse link
const tablesByLeg = {}
for (const table of result.data.table) {
for (const leg of table.legs) {
if (!tablesByLeg[leg.id]) {
tablesByLeg[leg.id] = {
leg: leg,
tables: []
}
}
tablesByLeg[leg.id].tables.push(table)
}
}
// write to the Apollo cache
for (const { leg, tables } of Object.values(tablesByLeg)) {
client.writeFragment({
id: dataIdFromObject(leg),
fragment: gql`
fragment reverseLink from Leg {
id
tables {
id
}
}
`,
data: {
...leg,
tables
}
})
}
// update component state
this.setState(state => ({
...state,
tables: Object.values(result)
}))
}
Демо
Я приведу полный пример здесь: https://codesandbox.io/s/6vx0m346z Я также поставил это ниже только для полноты.
index.js
import React from "react";
import ReactDOM from "react-dom";
import { ApolloProvider } from "react-apollo";
import { createClient } from "./client";
import { Films } from "./Films";
const client = createClient();
function App() {
return (
<ApolloProvider client={client}>
<Films />
</ApolloProvider>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
client.js
import { ApolloClient } from "apollo-client";
import { InMemoryCache } from "apollo-cache-inmemory";
import { HttpLink } from "apollo-link-http";
export function dataIdFromObject(object) {
return object.id ? object.__typename + ":" + object.id : null;
}
export function createClient() {
return new ApolloClient({
connectToDevTools: true,
ssrMode: false,
link: new HttpLink({
uri: "https://prevostc-swapi-graphql.herokuapp.com"
}),
cache: new InMemoryCache({
dataIdFromObject,
cacheRedirects: {
Query: {
planet: (_, args, { getCacheKey }) =>
getCacheKey({ __typename: "Planet", id: args.id })
}
}
})
});
}
Films.js
<code>import React from "react";
import gql from "graphql-tag";
import { withApollo } from "react-apollo";
import { dataIdFromObject } from "../src/client";
import { Planet } from "./Planet";
const ALL_FILMS_QUERY = gql`
query {
allFilms {
films {
id
title
planetConnection {
planets {
id
name
}
}
}
}
}
`;
const REVERSE_LINK_FRAGMENT = gql`
fragment reverseLink on Planet {
id
name
filmConnection {
films {
id
title
}
}
}
`;
class FilmsComponent extends React.Component {
constructor() {
super();
this.state = { films: [], selectedPlanetId: null };
}
componentDidMount() {
this.fetchFilms();
}
fetchFilms = async () => {
const result = await this.props.client.query({
query: ALL_FILMS_QUERY,
variables: {}
});
// compute the reverse link
const filmByPlanet = {};
for (const film of result.data.allFilms.films) {
for (const planet of film.planetConnection.planets) {
if (!filmByPlanet[planet.id]) {
filmByPlanet[planet.id] = {
planet: planet,
films: []
};
}
filmByPlanet[planet.id].films.push(film);
}
}
// write to the apollo cache
for (const { planet, films } of Object.values(filmByPlanet)) {
this.props.client.writeFragment({
id: dataIdFromObject(planet),
fragment: REVERSE_LINK_FRAGMENT,
data: {
...planet,
filmConnection: {
films,
__typename: "PlanetsFilmsConnection"
}
}
});
}
// update component state at last
this.setState(state => ({
...state,
films: Object.values(result.data.allFilms.films)
}));
};
render() {
return (
<div>
{this.state.selectedPlanetId && (
<div>
<h1>Planet query result</h1>
<Planet id={this.state.selectedPlanetId} />
</div>
)}
<h1>All films</h1>
{this.state.films.map(f => {
return (
<ul key={f.id}>
<li>id: {f.id}</li>
<li>
title: <strong>{f.title}</strong>
</li>
<li>__typename: {f.__typename}</li>
<li>
planets:
{f.planetConnection.planets.map(p => {
return (
<ul key={p.id}>
<li>id: {p.id}</li>
<li>
name: <strong>{p.name}</strong>
</li>
<li>__typename: {p.__typename}</li>
<li>
<button
onClick={() =>
this.setState(state => ({
...state,
selectedPlanetId: p.id
}))
}
>
select
</button>
</li>
<li> </li>
</ul>
);
})}
</li>
</ul>
);
})}
<h1>The current cache is:</h1>
<pre>{JSON.stringify(this.props.client.extract(), null, 2)}
);}} export const Films = withApollo (FilmsComponent);
Planet.js
import React from "react";
import gql from "graphql-tag";
import { Query } from "react-apollo";
const PLANET_QUERY = gql`
query ($id: ID!) {
planet(id: $id) {
id
name
filmConnection {
films {
id
title
}
}
}
}
`;
export function Planet({ id }) {
return (
<Query query={PLANET_QUERY} variables={{ id }}>
{({ loading, error, data }) => {
if (loading) return "Loading...";
if (error) return `Error! ${error.message}`;
const p = data.planet;
return (
<ul key={p.id}>
<li>id: {p.id}</li>
<li>
name: <strong>{p.name}</strong>
</li>
<li>__typename: {p.__typename}</li>
{p.filmConnection.films.map(f => {
return (
<ul key={f.id}>
<li>id: {f.id}</li>
<li>
title: <strong>{f.title}</strong>
</li>
<li>__typename: {f.__typename}</li>
<li> </li>
</ul>
);
})}
</ul>
);
}}
</Query>
);
}