Schedule > Activity: React Carousel from Server Data
Due Wed, 04/01 at 11:59pm
Learning Goals
By the end of this activity, you should be able to:
- use
useEffect()to run code after a component renders- fetch JSON data from a server using
fetch()- store fetched data in a state variable using
useState()- explain what the second array argument to
useEffect()does- adapt server data so it can be passed into an existing component as props
- fetch new data when the selected gallery changes
Starting Point
This activity builds directly on the previous React state activity.
Use your completed solution from
react-state-activity. If you need a fresh copy, you can download the solutions here:Don’t forget to install the dependencies!
Navigate to your React project folder on the command line. Then run:
npm install npm run dev
1. Let’s look at some server data from Flickr
Open this endpoint in your browser:
Notice that the server returns an array of objects. Each object has fields such as:
titleimg_url
In the previous activity, each gallery probably looked something like this:
const galleries = [
{
name: "Nature",
photos: ["...", "...", "..."]
},
{
name: "City",
photos: ["...", "...", "..."]
}
];
In this activity, each gallery should instead store an endpoint:
const galleries = [
{
name: "Cats",
endpoint: "https://www.apitutor.org/flickr/simple/?tags=cat"
},
{
name: "Dogs",
endpoint: "https://www.apitutor.org/flickr/simple/?tags=dog"
},
{
name: "Birds",
endpoint: "https://www.apitutor.org/flickr/simple/?tags=bird"
}
];
Your app will then fetch the photos for the currently selected gallery.
2. Complete the following tasks
In the previous activity, your photo data was hard-coded inside App.jsx. In this activity, you will replace that hard-coded data with server data.
4.1. Change your gallery data to use endpoints
Open App.jsx.
Keep your gallery chooser from the previous activity, but change the shape of each gallery object.
Instead of:
namephotos
each gallery should now have:
nameendpoint
For example:
const galleries = [
{
name: "Cats",
endpoint: "https://www.apitutor.org/flickr/simple/?tags=cat"
},
{
name: "Dogs",
endpoint: "https://www.apitutor.org/flickr/simple/?tags=dog"
},
{
name: "Birds",
endpoint: "https://www.apitutor.org/flickr/simple/?tags=bird"
}
];
Feel free to modify the categories and tags (or add more galleries). You should still keep state in App.jsx to track the currently selected gallery.
4.2. Create state for the fetched photos
Now create a second state variable to hold the photos you fetch from the server.
For example:
const [photos, setPhotos] = useState([]);
At this point, photos should start as an empty array.
4.3. Write an async helper function
Still inside App.jsx, write an async function that accepts an endpoint as an argument.
Inside your function:
- use
fetch(...)to request the data - use
await response.json()to turn the response into JavaScript data - convert the returned array of objects into an array of image URLs
- call
setPhotos(...)with that array
Here’s some sample code:
async function getPhotos(endpoint) {
// issue the request:
const response = await fetch(endpoint);
// extract the JSON from the request:
const data = await response.json();
// extract the photo urls from the flickr data:
const imageUrls = data.map((item) => item.img_url);
setPhotos(imageUrls);
}
Why are we using data.map(...) here?
Because your existing Carousel component already expects an array of image URLs. This lets you keep most of your previous Carousel code.
4.4. Use useEffect() to fetch when the selected gallery changes
Now import useEffect from React:
import React, { useEffect, useState } from "react";
Then add an effect that calls your getPhotos() function using the selected gallery’s endpoint.
useEffect(() => {
getPhotos(selectedGallery.endpoint);
}, [selectedGallery]);
This is the big new idea in this activity.
The second argument to useEffect() is the dependency array:
[]means “run this effect after the first render”[selectedGallery]means “run this effect again when the selected gallery changes”
In other words:
- when the app first loads, fetch the first gallery
- when the user clicks a different gallery, fetch new photos for that gallery
4.5. Render your Carousel using the fetched photos
Update your JSX so that the Carousel component receives the photos state variable instead of a hard-coded array.
For example:
<Carousel gallery={photos} />
At first, photos will be an empty array. A moment later, after the fetch finishes, React will update the state and redraw the component.
4.6. Add a loading message
Because the data comes from a server, the photos are not available immediately.
Add a small loading state to your JSX. For example:
- if
photos.length === 0, show a message likeLoading photos... - otherwise, render the
Carousel
This helps students see that server data arrives asynchronously.
4.7. Explain what changed
Once your code is working, make sure you can explain the following:
- Why do we use
useState()forphotos? - Why do we use
useEffect()forgetPhotos()? - Why is the selected gallery included in the dependency array?
- Why do we transform the server data with
map(...)before passing it toCarousel? - Why is each gallery storing an
endpointinstead of aphotosarray?
5. Recommendations
Here are some implementation recommendations:
- Keep the gallery-selection state in
App, just like you did in the previous activity. - Keep the fetched
photosin a separate state variable from the selected gallery. - Let
Gallerycontinue to be a simple chooser component that only cares about names and clicks. - Let
Carouselstay simple by continuing to receive just an array of image URLs. - Do the server-data transformation in
App, not insideCarousel. - Start with one working endpoint first, then add the other gallery endpoints after the pattern works.
6. Optional Challenge
Right now the endpoint examples use different tags.
See if you can add a caption somewhere on the page that shows the selected gallery name and the endpoint currently being used.
<p>Currently viewing: {selectedGallery.name}</p>