Fetching and Rendering Sanity Posts on your Homepage
Tags: react, nextjs, cms
Published: 2022-07-17 23:17:00

_Like in my last lesson, there will be a reference image of my file structure and file content so you can compare._

## Creating a Sanity client

We need to create a way for our app to fetch the data we store inside of Sanity. Luckily Sanity makes this very easy for us. You can read up more on what I'm using here. [Sanity Client](https://www.npmjs.com/package/@sanity/client)

```
npm i -g @sanity/client &&
npm i next-sanity
```

This will install the Sanity client globally to use for any project. 
We need to create a folder in our root named `lib` and a file within that folder named `sanity.js` and paste this code in your new file.

```javascript
const sanityClient = require("@sanity/client");
const client = sanityClient({
  projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
  dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,
  apiVersion: "2021-03-25", // use current UTC date - see "specifying API version"!
  useCdn: true, // `false` if you want to ensure fresh data
});

export default client;
```
_This code can be found on the Sanity Client package docs._

<hr />

## Fetching our posts

In your `/pages/index.js` file (_not your `/studio/schemas/index.js`_), at the bottom, you need to create an async/await function to fetch your data.

```javascript
export async function getStaticProps() {}
```
While at the top of this page you need to import the client we just created. 
```javascript
import client from "../lib/sanity";
```

You can, and should, read up on `getStaticProps` here [NextJS docs](https://nextjs.org/docs/basic-features/data-fetching/get-static-props).
On that page it will explain what this function does, how it works, and when to use it. One of the reasons to use it is if `The data comes from a headless CMS`, which is exactly how we plan to use it.

Inside of our new function we are going to make a [GROQ](https://www.sanity.io/docs/groq) query to tell it what data to look for, how to order the data, and what pieces of that data we want returned to us.

```javascript
export async function getStaticProps() {
  const query = `*[_type == "post"] | order(publishedAt desc) {
    _id,
    title,
    publishedAt,
    'slug': slug.current,
    body
  }`;

  const posts = await client.fetch(query);

  return {
    props: { posts },
  };
}
```

I'm going to break each part of this function down to make it easier to understand, because just copying and pasting code without the knowledge of what each piece means isn't going to be very useful later on.

- `` const query = `...` ``


 - Obviously this is just us declaring a variable for our query to 
use later. But what is important here is the fact that our code 
within the query is surrounded by back ticks.

- `*[_type == "post"]`

 - This is telling our client to grab every entry we have in our database that has a `name` of post
 - You can see that we named our entries back when we created our 'Post' schema. That is what this `"post"` query is referring to. 
![Post schema name example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ee00rvri6zdiclfoi0of.png)

- ` | order(publishedAt desc)`

 - Simple enough, this is telling our query to return the 'posts' that it fetched in an order by the published date in descending order. This means newest posts return first.


```javascript
 {
    _id,
    title,
    publishedAt,
    'slug': slug.current,
    body
  }
```

 - We are telling the fetch request what data we actually want returned. This is the power of GROQ, you only receive the data you want. Without this part you would get the entire 'post' data which looks something like this.

```javascript
{
    "_createdAt": "2022-07-17T00:48:06Z",
    "_id": "f026b8eb-0fc6-4a58-8494-789def2703ff",
    "_rev": "IvZ71YmXkO22WtmwIxDKV0",
    "_type": "post",
    "_updatedAt": "2022-07-17T00:48:06Z",
    "body": (5) [{…}, {…}, {…}, {…}, {…}],
    "publishedAt": "2022-07-17T00:45:31.070Z",
    "slug": {
        "_type": "slug",
        "current": "the-art-of-creating-a-post"
    },
    "title": "The art of creating a post"
}
```

That's way more information than we need. So we are going to tell our query to only return to us the _id, title, publishedAt, slug, and body.
For the curious, slug is written as `'slug': slug.current` because as you can see above, slug returns an object but we only need the `current` value, not the `_type`. So we are returning `slug.current` but assigning it to the `slug` key name.

- `` const posts = await client.fetch(query); ``

 - Simple fetch request that uses the `client` we created and imported in this lesson, the `query` variable we just added, and assigns the return to a new variable named `posts`

- `return { props: { posts } };`

 - Return props with our posts variable so our component can use it.

<hr />

## Rendering our posts

Back at the top of our `/pages/index.js` file we are currently in, we are going to add our `posts` variable we just fetched to our `Home` component. 
```javascript
export default function Home({ posts }) {
  return <h1>Hi :D</h1>;
}
```
_We are able to grabs our `posts` data from the `props` value by a method called `destructuring`._

Now to create HTML elements from our `posts` array. We will handle this by mapping over the data and saving it to a variable.

```javascript
const postsElements = posts.map((post, index) => (
    <div key={index}>
      <p>{new Date(post.publishedAt).toDateString().slice(4)}</p>
      <h3>{post.title}</h3>
    </div>
  ));
```
This will return a `div` with a `p` and `h3` tag for each post we have.
We need the outer `div` simply because you need multiple elements to be wrapped in 1 so you can return it. Returning the `p` and the `h3` without wrapping it in something will throw an error. We also add the `key` to this with the `index` of it's position in the array so React doesn't scream at us. (this is very useful to read up on, it gave me hours of debugging when I started learning React).

We add a `p` tag with the `publishedAt` value turned into a Date, turned into a string so HTML can read it, and we `slice` off the first 4 characters of the string (essentially removing the day of the week).

And finally an `h3` with the `title` of our post.

Now if you add this variable in your return (_wrapping it again in an outer div for the same reason as above, you must return 1 outer HTML element_) like this. 
```javascript
return <div>{postsElements}</div>
```
Closing your current `npm run dev` and starting it again you should see all of your posts (but only the title and published date) on your homepage by date they were published.


![Posts rendered to homepage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xb7aouybq8wrr9aazza4.png)

It's quite ugly right now, but that's not the point. I will create a future lesson, or maybe edit this one, to add the methods I'm going to use to style it. I just want to get this out in the meantime to help people that need it.

<hr />

## Upcoming lessons

That's everything for this part. I might have went overboard explaining every little detail, but all of these concepts are very fundamental and will be reused later in this project (and most likely in your future projects). So I wanted to help you get a grasp of how everything works so you will have the knowledge to explore and make something yourself.

In the next part I will explain how to create dynamic urls for your posts so you can see the full information for it on it's on page.

<hr />

## References

### - File Structure

![Lesson 4 File Structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vohw71rb0zf7zq5p4v3h.png)

### - /pages/index.js 

```javascript
import client from "../lib/sanity";

export default function Home({ posts }) {
  const postsElements = posts.map((post, index) => (
    <div key={index}>
      <p>{new Date(post.publishedAt).toDateString().slice(4)}</p>
      <h3>{post.title}</h3>
    </div>
  ));
  return <div>{postsElements}</div>;
}

export async function getStaticProps() {
  const query = `*[_type == "post"] | order(publishedAt desc) {
    _id,
    title,
    publishedAt,
    'slug': slug.current,
    body
  }`;

  const posts = await client.fetch(query);

  return {
    props: { posts },
  };
}

```

### - /lib/sanity.js

```javascript
const sanityClient = require("@sanity/client");
const client = sanityClient({
  projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
  dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,
  apiVersion: "2021-03-25", // use current UTC date - see "specifying API version"!
  useCdn: true, // `false` if you want to ensure fresh data
});

export default client;
```