Search code examples
reactjsgraphqlapollo

How to call GraphQL outside a component


I have made a bunch of React component calling GraphQL using the Query component and everything is working fine.

In one component I need to have some initial data from the database, but without any visual representation.

I have tried to use the query component but it seems to be triggered only on the render cycle. I have tried to package it into a function and call this function in the component that needs the data. But the code / query is not executed since there's no component to show.

How do I go about getting this data from the database without a component?

I can't find any documentation on how to solve this problem. But I can't be the only one doing this.

Is ApolloConsumer or ApolloProvider the answer to my problems?

I'm working with conferences and sessions. A conference runs over a couple of days and each day has a number of sessions.

What I'm trying to achieve is to render a page with X numbers of tabs one for each day. Each tab represents a day and it shows the number of sessions for the day.

My sessions page:

    import React from 'react';
import FullWidthTabs from '../components/Sessions';
import SessionTab from '../components/SessionTab';
import BwAppBar2 from '../components/BwAppBar2';
import ConferenceDays from '../components/ConferenceDays';


class SessionsPage extends React.Component {

    static async getInitialProps() {
        console.log("GetInitProps SessionsPage");
    }

    render() {
        let a = ConferenceDays();
        return (

                <div>
                    <BwAppBar2 />
                    {a}
                     <FullWidthTabs days={['2018-06-11', '2018-06-12', '2018-06-13']} day1={ < SessionTab conferenceId = "57" day = '2018-06-11' / > } 
                                   day2={ < SessionTab conferenceId = "57" day = '2018-06-12' / > } day3={ < SessionTab conferenceId = "57" day = '2018-06-13' / > }>
                    </FullWidthTabs>
                </div>
                );
        }
}
export default (SessionsPage);

Here the dates have been hardcoded in the page just for testing.

But order to know how many days the conference spans i'll have to find the conference and decide the start and end date and generate all the dates in between:

import React, { Component } from 'react'
import { graphql } from 'react-apollo'
import { Query } from 'react-apollo'
import gql from 'graphql-tag'
import Link from '@material-ui/core/Link';
import { useQuery } from "react-apollo-hooks";

import conferencesQuery from '../queries/conferences'
import { Table, Head, Cell } from './Table'
import ConferenceCard from './ConferenceCard';
import Grid from '@material-ui/core/Grid';
import Paper from '@material-ui/core/Paper';
import moment from 'moment';


const CONFERENCE_QUERY = gql`
 query conference($conferenceId : ID!){
      conference(id: $conferenceId){
          title
          start_date
          end_date
     }    
}
`
let index = 0;
let loopDate = 0;
let dates = [];
let conferenceId = 57;

const ConferenceDays = () => (
<Query query={CONFERENCE_QUERY} variables={{conferenceId}}>
    {({ loading, error, data }) => {
                        if (loading)
                            return <div>Fetching</div>
                        if (error)
                            return <div>Error</div>
                        const startDate = moment(data.conference.start_date, 'x');
                        const endDate = moment(data.conference.end_date, 'x');

                        for (loopDate = parseInt(data.conference.start_date);
                                loopDate < parseInt(data.conference.end_date);
                                loopDate += 86400000) {

                            let aDate = moment(loopDate, 'x');
                            dates.push(aDate.format('YYYY-MM-DD').toString());
                        }
                        console.log(dates);
                        return(dates);
                    }}
</Query>);

export default ConferenceDays

But is this approach incorrect?

Would it be more correct to lift the ConferenceDates component up in the hierarchy?

Kim


Solution

  • If you are using functional components, you can use useApolloClient hook in a function as though it is not a hook.

    import { useApolloClient, gql } from "@apollo/client";
    
     MY_QUERY = gql'
       query OUR_QUERY {
         books{
            edges{
               node{
                 id
                 title
                 author
                }
             }
          }
       }
    '
    
    const myFunctionalComponent = () => {   // outside function component
    
        const client = useApolloClient();
    
        const aNormalFunction = () => {   // please note that this is not a component  
           client.query({
              query: MY_QUERY,
              fetchPolicy: "cache-first"   // select appropriate fetchPolicy
           }).then((data) => {
              console.log(data)   //do whatever you like with the data
           }).catch((err) => {
              console.log(err)
           })
        };
    
        // just call it as a function whenever you want
        aNormalFunction()    
        
        // you can even call it conditionally which is not possible with useQuery hook
        if (true) {
            aNormalFunction()
        }
    
        return (
            <p>Hello Hook!</>
        );
    };
    
    export default myFunctionalComponent;