0

I am trying to create a dummy project with React JS and Im getting my data from SpaceX Graphql API. I have two components (Home, Details) and both components are supposed to grab data from the API. However, I query works in the Home component but it does not in the Details component. I used the exact same method and it doesn't seem to work. Do help me with this.

You can try the whole thing at https://github.com/affiqzaini/react-apollo-spacex if you want.

Here's my Home component which works:

import React from 'react';
import { Query } from 'react-apollo';
import gql from 'graphql-tag';
import { BrowserRouter, NavLink } from 'react-router-dom';
import Route from 'react-router-dom/Route';
import 'react-bulma-components/dist/react-bulma-components.min.css';
import './App.css';
import Details from './Details';

const POSTS_QUERY = gql`
  {
    rockets {
      name
      country
      id
    }
  }
`;

function Home() {
  return (
    <BrowserRouter>
      <Route
        path='/'
        exact
        strict
        render={() => {
          return (
            <div
              className='tile is-ancestor'
              style={{
                justifyContent: 'space-evenly',
                alignItems: 'center',
                margin: 25
              }}
            >
              <Query query={POSTS_QUERY}>
                {({ loading, data }) => {
                  if (loading) return <p className='Loading'>Loading...</p>;
                  const { rockets } = data;
                  return rockets.map(post => (
                    <NavLink to={{ pathname: `/${post.id}` }}>
                      <div class='tile is-parent'>
                        <article
                          class='tile is-child box'
                          key={post.id}
                          style={{
                            backgroundColor: 'whitesmoke',
                            borderRadius: 10,
                            height: 400,
                            width: 300
                          }}
                        >
                          <figure
                            class='image container is-1by1'
                            style={{ marginBottom: 15 }}
                          >
                            <img
                              src={require(`./Images/${post.id.toString()}.jpg`)}
                              className='Rocket-Img'
                              alt='Rocket'
                            />
                          </figure>
                          <h2>{post.name}</h2>
                          <h4>{post.country}</h4>
                        </article>
                      </div>
                    </NavLink>
                  ));
                }}
              </Query>
            </div>
          );
        }}
      />
      <Route path='/:id' exact strict component={Details} />
    </BrowserRouter>
  );
}

export default Home;

Here's my Details component which does not work:

import React from 'react';
import { useParams } from 'react-router';
import { Query, ApolloProvider } from 'react-apollo';
import gql from 'graphql-tag';
import ApolloClient from 'apollo-boost';
import './App.css';

function Details() {
  const rocketId = useParams();
  const QUERY_ROCKET = gql`
    {
      rocket(id: "${rocketId}") {
        id
        active
        boosters
        company
        cost_per_launch
        name
        stages
        success_rate_pct
        type
        wikipedia
        first_flight
        country
        description
      }
    }
  `;

  return (
    <Query query={QUERY_ROCKET}>
      {({ loading, data }) => {
        if (loading) {
          return <p className='Loading'>Loading...</p>;
        } else {
          const { detailsData } = data;
          return detailsData.map(post => (
            <div>
              <p>{post.id}</p>
            </div>
          ));
        }
      }}
    </Query>
  );
}
export default Details;

Here's the error I get: Error Image

Update: I found out that I get different type of data in the two queries. In Home (which works), I get an array of data. In my details component, I get an object. Is that why I cant use the map function?

2
  • detailsData is undefined. Are you sure it's returned in your data object? Commented Mar 26, 2020 at 6:24
  • I do get the data. But it's not in an array like in the Home component. It's just an object. How do I use that object? Commented Mar 26, 2020 at 14:58

3 Answers 3

1

According to Query docs https://www.apollographql.com/docs/react/v2.5/essentials/queries/ you don't need to use "else" after this:

if (loading) return <p className='Loading'>Loading...</p>;

And you don't do that in your Home component which works. Try to remove "else" as well in your Details component:

<Query query={QUERY_ROCKET}>
  {({ loading, data }) => {
    if (loading) return <p className='Loading'>Loading...</p>;
    const { detailsData } = data;
    return detailsData.map(post => (
      <div>
        <p>{post.id}</p>
      </div>
    ));
  }}
</Query>
Sign up to request clarification or add additional context in comments.

3 Comments

I didnt use else originally. It didnt work too. I put it just to try something else and I forgot to remove it.
Then maybe you can try this: const { detailsData } = data && data;
It still doesn't work. Feel free to try it if you want. github.com/affiqzaini/react-apollo-spacex
0

If the returned data you want to map is still in object form then you need to convert the object to an array.

Object.values(data.detailsData) to get an array of just the values, or Object.entries(data.detailsData) to get an array of the key-value pairs, i.e. [[key1, value1], [key2, value2], ...[keyN, valueN]].

Object.values

The Object.values() method returns an array of a given object's own enumerable property values, in the same order as that provided by a for...in loop.

Object.entries()

The Object.entries() method returns an array of a given object's own enumerable string-keyed property [key, value] pairs, in the same order as that provided by a for...in loop.

return Object.values(detailsData).map(post => (
  <div>
    <p>{post.id}</p>
  </div>
));

Comments

0

I found out that the data that I'm getting is in an object form instead of an array. To access the object, you can either use DrewReese's method above or the this way which I find to be simpler:

*** 'rocket' is the name of my object

return (
    <Query query={QUERY_ROCKET}>
      {({ loading, error, data }) => {
        if (loading) return <p className='Loading'>Loading...</p>;
        if (error) return `Error! ${error.message}`;

        const detailsData = data.rocket;
        return (
          <div>
            <p>{detailsData.id}</p>
            <p>{detailsData.name}</p>
            <p>{detailsData.company}</p>
            <p>{detailsData.stages}</p>
            <p>{detailsData.boosters}</p>
            <p>{detailsData.cost_per_launch}</p>
          </div>
        );
      }}
    </Query>

1 Comment

Awesome! I'm not familiar with graphQL, so without digging into a bunch of documentation I don't think I would have arrived to this conclusion for a while. Yes, if your result object is the object you want to display then simply accessing the fields/properties is better, especially if you treat each one differently. Nice.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.