I am using Apollo GraphQL to fetch posts to populate a next js project.
The code I currently have works but I would like to implement the loading state of useQuery instead of what I have below.
This is the index (Posts page if you will)
import Layout from "../components/Layout";
import Post from "../components/Post";
import client from "./../components/ApolloClient";
import gql from "graphql-tag";
const POSTS_QUERY = gql`
query {
posts {
nodes {
title
slug
postId
featuredImage {
sourceUrl
}
}
}
}
`;
const Index = props => {
const { posts } = props;
return (
<Layout>
<div className="container">
<div className="grid">
{posts.length
? posts.map(post => <Post key={post.postId} post={post} />)
: ""}
</div>
</div>
</Layout>
);
};
Index.getInitialProps = async () => {
const result = await client.query({ query: POSTS_QUERY });
return {
posts: result.data.posts.nodes
};
};
export default Index;
Then it fetches an individual Post
import Layout from "../components/Layout";
import { withRouter } from "next/router";
import client from "../components/ApolloClient";
import POST_BY_ID_QUERY from "../queries/post-by-id";
const Post = withRouter(props => {
const { post } = props;
return (
<Layout>
{post ? (
<div className="container">
<div className="post">
<div className="media">
<img src={post.featuredImage.sourceUrl} alt={post.title} />
</div>
<h2>{post.title}</h2>
</div>
</div>
) : (
""
)}
</Layout>
);
});
Post.getInitialProps = async function(context) {
let {
query: { slug }
} = context;
const id = slug ? parseInt(slug.split("-").pop()) : context.query.id;
const res = await client.query({
query: POST_BY_ID_QUERY,
variables: { id }
});
return {
post: res.data.post
};
};
export default Post;
Whenever I have tried to use the useQuery with '@apollo/react-hooks' I always end up with a data.posts.map is not a function.
When you use useQuery
, you should not destructure the data like result.data.posts.nodes
because the data field will be undefined
and loading
is true for the first time calling. That why you got an error data.posts.map is not a function
. Then if your query fetch data successfully, the loading
field will be false.
You can try it:
import Layout from "../components/Layout";
import Post from "../components/Post";
import client from "./../components/ApolloClient";
import { useQuery } from "@apollo/react-hooks"
import gql from "graphql-tag";
const POSTS_QUERY = gql`
query {
posts {
nodes {
title
slug
postId
featuredImage {
sourceUrl
}
}
}
}
`;
const Index = props => {
const { posts } = props;
const { loading, error, data } = useQuery(POSTS_QUERY);
if (loading) return <div>Loading...</div>
if (error) return <div>Error</div>
return (
<Layout>
<div className="container">
<div className="grid">
{data.posts.nodes.length
? data.posts.nodes.map(post => <Post key={post.postId} post={post} />)
: ""}
</div>
</div>
</Layout>
);
};