简体   繁体   中英

Cannot read property 'map' of undefined (ReactJS-Apollo-Graphql)

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?

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>

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, ie [[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>
));

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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM