Now that we have a basic site with two pages, it’s time to look at how we can get some content onto these pages. We don’t just want to type some text on there and have static content, we want to be able to pull in data from other sources and display dynamic content based on user input.
Before we get into really cool APIs and integrate AI into our app, there are some basic concepts and principles we must learn. The first step to doing that is to learn how to connect to a very simple API and fetch some data, so let’s get started and build from there.
Fetching data from an API
For the first example, we’ll use a free fake API that is provided for testing and provides some dummy JSON data. Go to https://jsonplaceholder.typicode.com/todos in your browser and you’ll see something like this:

Now it may not look this neatly formatted on your screen, as that is the work of a browser extension, but you should see the same data. This is the data that we’re going to fetch into our website and display on the page.
First, open up your page.tsx file in the blockbuster_chat folder. There’s not much in here currently so we’re basically going to start from scratch. Just remove everything and let’s start anew:
import React from 'react'
interface Todo {
userId: number;
id: number;
title: string;
completed: boolean;
}
We import React as we always do, and now we define an interface just like last time because we know we’re going to have to deal with data in this particular format. This is simply a template that matches the data keys and types that we saw on the website just a moment ago.
The function standard framework is as follows, which is the same as it has always been so far:
const BlockBusterChat = () => {
return (
<div>
BlockBusterChat
</div>
)
}
export default BlockBusterChat
Notice that we can take some action though after the { opens and before the return() statement begins. Before we return anything, we need to fetch some data, so let’s do that now (again don’t worry about the red squiggly lines, we’ll get to it!):
const BlockBusterChat = () => {
const res = await fetch('https://jsonplaceholder.typicode.com/todos')
const todo_list: Todo[] = await res.json()
return (
<div>
BlockBusterChat
</div>
)
}
export default BlockBusterChat
We added two lines of code to run before we get to our return statement. We define a const named res which is short for response, and we use the fetch function to get the data from the URL we provided. As fetching data from an API requires a bit of time, the fetch function returns what JavaScript calls a promise.
This simply means that JavaScript is promising to give us the data as soon as it arrives. We use the await keyword to wait for the data to arrive, assigning it to the res constant before we move on to the next line of code.
The res constant object now contains the raw data received from the API, but it’s not in a format that we can use yet. We need to convert it to a format that we can work with, and that’s where the res.json() function comes in. This function parses the data into an object that we can work with, and we assign it to the todo_list constant.
The : Todo[] part is a type assertion, which tells TypeScript that the todo_list constant is an array of Todo objects. The reason we use the await keyword again is that the res.json() function also returns a promise, so we need to wait for it to resolve before we can use the data.
You’ll notice the red lines in your code editor:

This is happening because we used the await keyword inside a normal function. We need to make the function async or asynchronous to be able to use the await keyword. So let’s do that now:
const BlockBusterChat = async () => {
const res = ...
All you have to do is add the async keyword before the () => part of the function definition. This tells JavaScript that the function is asynchronous and that it contains await keywords that need to be resolved before the function can continue.
Mapping over the data
Ok so now we have an array of Todo objects in the todo_list constant, but we’re not doing anything with it yet. This is where we make the link with the return() portion of the function. Let’s display it on the page:
const BlockBusterChat = async () => {
const res = await fetch('https://jsonplaceholder.typicode.com/todos')
const todo_list: Todo[] = await res.json()
return (
<>
<h1 className='font-bold'>Blockbuster Chat</h1>
<ul>
{todo_list.map(todo => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
</>
)
}
export default BlockBusterChat
The first thing I want to point out is the <> and </> tags are the outer-most ones inside the return statement. These are called React fragments and they allow us to return multiple elements from a component without having to wrap them in a single parent element.
If you try to return and <h1> and a <ul> element that is two different elements, and you’ll get an error. The fragment acts as a container making it into a single element which is a requirement for React.
We then simply have a heading h1 where we use the font-bold class from Tailwind CSS to make it bold and display some heading text. After that is our ul element which is a list element where we display the list of todos we fetched.
The following might be confusing if you haven’t seen this before, so let’s peel off the layers one by one:
- The outer
{}brackets are again just to switch into JavaScript mode inside the return statement. - The
todo_list.map()function is a JavaScript function that iterates over each item in thetodo_listarray and returns a new array with the results of the function we provide. - The
map()function takes a function as an argument, which is called for each item in the array. We use an arrow functiontodo => ()to define the function. It’s a bit like Python and sayingfor todo in todo_list: do something. - So the input to the function inside map() is
todo, which we then take=>and we return when is inside the next()brackets. This is the JSX code that will be returned for each item in the array. - We return a
<li>item and show the todo.title for each todo inside the list. - We use the
keyattribute to give each list item a unique key. This is a requirement in React and helps React keep track of which items have changed, been added, or been removed. We can just use theidfield from thetodoobject as the key as they are unique.
If you now refresh the page you will see a list:

Now let’s fix it up a bit, change the content of the <ul>:
{todo_list.map(todo => (
<li key={todo.id}>{todo.id}. {todo.title} - {todo.completed ? 'Completed' : 'Not completed'}</li>
))}
We added a bit more information to each list item. We show the id of the todo, then the title, and then we check if the completed field is true or false and display a message accordingly using Javascript’s ternary operator. (statement or variable ?(if) return this if true :(else) return this if false)

Awesome, you now have live data on your website!
