0

I'm working with two API endpoints. The first one returns a list of dates in a string format for which data is available. The date can then be added to the second endpoint and renders additional data. On the Graphql Playground I have been able to make it all work. On the front-end I have a select option drop down for the dates, but I have not been able to fire off the second API call when I click on any given date. It's the first time I'm using graphql mutation and I haven't been able to get the second API request to return any data when I select a date. Thank you.

Front-end code:

app.tsx


import * as React from 'react'
import { useState } from 'react'
import { useMutation } from '@apollo/react-hooks'
import { IrriSatQuery } from '../../generated/graphql'
import { MAP_LAYER } from './query'

interface Props {
  data: IrriSatQuery;
}

const IrriSat: React.FC<Props> = ({ data }) => {
  const [option, setOption] = useState((data?.mapDates as any)[0].date!)
  const [getLayer] = useMutation(MAP_LAYER)

  return (
    <>

    <ContentWrapper>
      <select value={option} onChange={( e: React.ChangeEvent<HTMLSelectElement>, ): void => {setOption(e.target.value, getLayer(e.target.value)}} onSelect={() => getLayer({variables: {type: option}})}>
        {data?.mapDates?.slice(0,52).map(res => 
          <option key={res?.date!} value={res?.date!}>{res?.date}</option>
          )
        }
      </select>
    </ContentWrapper>
    </>
  )
}

export default IrriSat

query.ts


export const QUERY_IRR_SAT = gql`
 query IrriSat {
   mapDates {
     date
     dateurl
   }
 }
`

export const MAP_LAYER = gql`
  mutation MapLayer($date: String!) {
     mapDate(date: $date) {
       token
       mapid
       name
     }

   }
`

Back-end code:

server.js

class IrriSatAPI extends RESTDataSource {
  constructor() {
    super();
    this.baseURL = 'https://irrisat-cloud.appspot.com/_ah/api/irrisat/v1/services/'
  }

  async getMapsDates() {
    const response = await this.get('maps/dates')
    return Array.isArray(response.items) ? response.items.map(response => this.mapsDatesReducer(response)) : []
  }

  mapsDatesReducer(response) {
    return {
      date: response.date,
      dateurl: response.dateurl,
    }
  }

  async getMapsLayer(date) {

    const response = await this.get(`maps/layers/${date}`)
    return Array.isArray(response.items) ? response.items.map(response => this.mapsLayerReducer(response)) : []
  }

  mapsLayerReducer(response) {
    return {
      token: response.token,
      mapid: response.mapid,
      name: response.name
    }
  }


  }
}

schema.js

  type MapDates {
    date: String
    dateurl: String
  }

  type Mutation {
    mapDate(date: String): [MapsLayers]
  }

  type Query {
    mapDates: [MapDates]

resolver.js

module.exports = {
  Query: {
    mapDates: (_, __, { dataSources }) => dataSources.irriSatAPI.getMapsDates(),
  },
  Mutation: {
    mapDate: (_, { date }, { dataSources }) => dataSources.irriSatAPI.getMapsLayer(date)
  }
}
Alex Mireles
  • 121
  • 1
  • 7
  • not fired at all? render links/buttons in a loop (to learn how to use variables) - check dev tools/network (to check if request fired) ..... no mutation result data used (you can use 'onCompleted' handler option of mutation - with another setState - why overwriting data from props? use some 'selectedDate'?) ... you can use `useEffect` to call **normal query** (not mutation) on `option` change (effect dependency, effect fired at start and forced by `setOption`) because you're not changing remote data ... rethink your data state and flow – xadm Apr 23 '20 at 11:05

1 Answers1

1

There are a few issues with your onChange function.

You are calling getLayer twice? You should only need to call it once, at the same time as you set the value of the dropdown. Also, as far as I know, you don't really need the onSelect.

import * as React from 'react';
import { useState } from 'react';
import { useMutation } from '@apollo/react-hooks';
import gql from 'graphql-tag';

const MAP_LAYER = gql`
    mutation MapLayer($date: String!) {
        mapDate(date: $date) {
            token
            mapid
            name
        }
    }
`;

const ContentWrapper = ({ children }) => <div>{...children}</div>;

const IrriSat: React.FC<any> = ({ data }) => {
    const [option, setOption] = useState((data?.mapDates as any)[0].date!);
    const [getLayer]: any = useMutation(MAP_LAYER);

    return (
        <ContentWrapper>
            <select
                value={option}
                onChange={(e: React.ChangeEvent<HTMLSelectElement>): void => {
                    setOption(e.target.value);
                    getLayer({ variables: { date: e.target.value } });
                }}
            >
                {data?.mapDates?.slice(0, 52).map(res => (
                    <option key={res?.date!} value={res?.date!}>
                        {res?.date}
                    </option>
                ))}
            </select>
        </ContentWrapper>
    );
};

export default IrriSat;

Obviously, I changed a few things to get rid of some of the editor warnings, but pay particular attention to the onChange property.

A tip: you are probably experiencing these issues due to the extreme length of the line that you add all of this logic condensed into. Install the "Prettier - Code formatter" VS Code extension. Enable VS Code's format on save option. Profit.

davidmwhynot
  • 386
  • 2
  • 10
  • Yeah I forgot to remove the onSelect when I posed the question. I didn't mean to call getLayer twice. Anyway, they key so far was to set the getLayer variable to "date". I now get the data in GraphiQL in DevTools. I still need to figure out how to actually access the data. Really appreciate your help. – Alex Mireles Apr 24 '20 at 19:14