Coherent
Coherent

Reputation: 2113

How to convert HOC to react component syntax for apollo?

Could anyone help me understand how I can abstract away apollo graphQL logic to convert between using apollo with HOC versus using the more modern <Query>({data, loading})=>(<MyComponent data={data} loading={loading}/>)</Query> syntax? Or if I can't do that, how you can use HOCs in a sub component that is not the whole page itself? I'm using next-apollo-appsync to handle all of my graphQL issues:

import { withAppSyncData } from "next-apollo-appsync";
import AppSyncConfig from "./aws-exports";

const config = {
  url: AppSyncConfig.aws_appsync_graphqlEndpoint,
  region: AppSyncConfig.aws_appsync_region,
  auth: {
    type: AppSyncConfig.aws_appsync_authenticationType,
    apiKey: AppSyncConfig.aws_appsync_apiKey
  }
};

export default withAppSyncData(config);

Once I create a withData function with my appsync settings, I use the withData function to create a TodosWithData function.

import withData from "../../lib/withData";
import gql from "graphql-tag";
import { graphql } from "react-apollo";

const query = gql`
  query listTodos {
    listTodos {
      items {
        id
        name
        completed
      }
    }
  }
`;

const TodosWithData = MyComponent =>
  withData(
    graphql(query, {
      options: {
        fetchPolicy: "cache-and-network"
      },
      props: props => ({ todos: props.data.listTodos ? props.data.listTodos.items : [] })
    })(MyComponent)
  );

export default TodosWithData;

This function will take a react component as an input and will return apollo wrapped around the component, and we'll have access to the data under this.props.data, just like we'd expect. The weird thing is that I can get this dumb component below to work, but only if it is on the page level- it does not work if I move it to a component that I load from a page.

import React from "react";
import TodosQuery from "../graphql/components/todos";

class Todos extends React.Component {
  render() {
    console.log(this.props); //We have access to the apollo payload
    return (
      <div>
        <p>Static Text</p>
      </div>
    );
  }
}

//This is what injects apollo payload into the Todos dumb-component.
export default TodosQuery(Todos); 

Here is a working repo for reference. The actual error I get is Cannot read property 'apollo' of undefined

Upvotes: 0

Views: 336

Answers (1)

Thomas Hennes
Thomas Hennes

Reputation: 9949

To elaborate on my comment, and using the <Query> syntax:

In src/index.js:

import React from "react";
import withData from "../lib/withData";
import TodosWithData from "../graphql/components/todos";

class App extends React.Component {
  render() {
    console.log("props: ", this.props);
    return (
      <div>
        <p>Hello World</p>
        <TodosWithData />
      </div>
    );
  }
}

export default withData(App);

In src/graphql/components/todos.js:

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

const query = gql`
  query listTodos {
    listTodos {
      items {
        id
        name
        completed
      }
    }
  }
`;

const TodosWithData = () => (
  <Query query={query} fetchPolicy="cache-and-network">
    {({ loading, error, data: { listTodos } }) => {
      if (error) return <div>Error loading todos</div>
      if (loading) return <div>Loading...</div>
      return (
        <div>
          <ul>
            {listTodos.items.map(todo => (
               <li key={todo.id}>{`${todo.name}${todo.completed ? " - DONE" : ""}`}</li>
            ))}
          </ul>
        </div>
      )
    }}
  </Query>
);

export default TodosWithData;

Upvotes: 1

Related Questions