Dear students:
Welcome to lab. Your task today is to work on project 3. This task is mostly open-ended, but these things must be done to receive today’s lab credit:
The project must be live by the end of the day. You will receive an invitation for peer reviews early on Friday and will have until Sunday to complete them. It is paramount that you complete these in a timely manner. You have through Monday, December 13, to address any issues that your peers identify. On Tuesday, I will start grading projects.
During the final exam period, you will present your project to the class in a lightning talk. Credit for your talk will be based on the following:
The final exam period is on Thursday, December 16, from 8-10 AM. I will see about bringing in some Strites donuts. As far as I’m aware, these are the only real donuts in this town.
The next step of your learning is to complete the following tasks:
See you next time.
Dear students:
Welcome to lab. Your task today is to work on project 3. This task is mostly open-ended, but these things must be done to receive today’s lab credit:
Remember that the project must be completed by the end of Thursday, December 9. You will receive one last invitation of peer reviews early on Friday and will have until Sunday to complete them. It is paramount that you complete these in a timely manner.
The next step of your learning is to complete the following tasks:
See you next time.
Dear students:
Welcome to lab. Now’s your chance to apply the ideas you read about. Find a partner and complete as much of the task below as you can. To receive credit for today’s lab, you as an individual must show your completed tasks to your instructor by the end of the day.
Your first task is to finish implementing the Dukebox app you started last time. Ensure that each team member has a local copy of the source directory. If you are using Live Share, collaborators can right-click on the shared folder and download it.
Add a progress indicator that displays while each fetch is in progress. You want it to display right before the fetch starts and hide after the fetch finishes. Add a flag to your Redux store that indicates whether or not the app has a background task in progress. Then conditionally render a progress indicator:
{isProgressing && <div className="spinner" />}
This flag must be set to true right before a fetch starts and set to false when it finishes. Your thunk creators are the perfect place to orchestrate this sequence. For example, you might write something like this:
function thunkCreator() {
return dispatch => {
dispatch(showProgress());
fetch(url)
.then(...)
.then(data => {
// ...
dispatch(hideProgress());
});
};
}
If you have time, feel free to design your own progress indicator. Otherwise, use this one from W3 Schools:
.spinner {
border: 16px solid #f3f3f3; /* Light grey */
border-top: 16px solid #3498db; /* Blue */
border-radius: 50%;
width: 120px;
height: 120px;
animation: spin 2s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
Your final task is for each individual to deploy your app to your droplet so that it’s available at https://dukebox.YOUR-DOMAIN-NAME. You do this by running the following command in your React project:
npm run build
Notice that a new directory named build appears inside the top-level of your project. This folder must not be put in version control. It can be rebuilt at any time. In general, you should add this directory to your .gitignore file.
On your droplet, create a folder named dukebox in your home directory, presumably right next to your project1 directory. Copy the files from your local build directory to your remote dukebox directory. If you’re on a machine with Unix utilities, you can run the secure copy (scp) command:
scp -r build/* YOUR-DOMAIN-NAME:dukebox
If you don’t have scp, try WinSCP. Or something else. I don’t know Windows. As a last resort, you can clone your React project on your droplet and build it there.
Add an Apache virtual host for your app as you did in project 1. You’ll need to set permissions on the dukebox directory and add a .conf file. Consult previous tutorial posts to remind yourself how this is done. Use HTTPS, and redirect HTTP traffic to HTTPS. You’ll need to follow the steps in the book to mark sure the paths are correctly handled by Apache.
The next step of your learning is to complete the following tasks:
See you next time.
Dear students:
Welcome to lab. Now’s your chance to apply the ideas you read about. Find a partner and complete as much of the task below as you can. At the end of our time together, paste your files into Crowdsource in order to receive credit.
Your task is in this lab is to create a multi-page client for a music streaming service. The client has three pages:
Clicking on an artist takes the user to the albums page. Clicking on an album takes the user to the tracks page. To keep this exercise manageable, your client will not actually play any music. Extending it to really play music is something to do when all the homework’s turned in.
Create a new React app and strip out the boilerplate code as you have done in the past. Install these helper libraries: react-redux, react-router-dom, and redux-thunk.
Add a component for each page. Initially, just have each component render a heading that clearly identifies which component is visible.
Choose which page is displayed using the Router library. Ensure that you can visit each page by manually adjusting the path.
Now create a global Redux store that holds the model behind each page. Ultimately you will fill this store with data you pull down from a web service. But don’t start there. For the moment, pre-populate your store with this initial state:
const initialState = {
artists: [
'The Album Leaf',
'Balmorhea',
'Library Tapes',
'Nils Frahm',
'Ólafur Arnalds',
],
// These a Balmorhea's albums...
albums: [
'Balmorhea',
'Rivers Arms',
'All Is Wild, All Is Silent',
'Constellations',
'Stranger',
'Clear Language',
'The Wind',
],
// These are the tracks of Rivers Arms...
tracks: [
'San Solomon',
'Lament',
'The Summer',
'The Winter',
'Greyish Tapering Ash',
'Baleen Morning',
'Barefoot Pilgrims',
'Context',
'Process',
'Divisadero',
'Limmat',
'Theme No. 1',
'Windansea',
'San Solomon (Reprise)',
],
};
Have each component pull out the relevant data from this store and display it in lists. Make each artist a Link to the albums page, with the artist passed in as a parameter. Make each album a Link to the tracks page, with the album and artist passed in as parameters.
Instead of pre-populating the initial state, pull down the data using thunk creators that call fetch. You are encouraged to implement this by following these steps:
actions.js, add an Action enum with the following keys: LoadArtists, LoadAlbums, LoadTracks.fetchArtists. It pulls down an array of artists from https://dukebox.twodee.org:8443/artists and drops them into the store.useEffect in the App component.fetchAlbums. It accepts the artist name as a parameter and pulls down an array of albums for an artist from https://dukebox.twodee.org:8443/artists/ARTIST and drops them into the store. ARTIST must be replaced by the artist’s actual name.useEffect in the albums component.fetchTracks. It accepts the artist and album names as parameters and pulls down an array of tracks from https://dukebox.twodee.org:8443/artists/ARTIST/ALBUM and drops them into the store. ARTIST and ALBUM must be replaced by the artist’s and album’s actual names.useEffect in the tracks component.Once a fetch finishes and dispatches a Load* action, the store will be updated by the reducer. Any component that has called useSelector to pull out the changed state will automatically re-render.
The next step of your learning is to complete the following tasks:
See you next time.
Dear students:
Welcome to lab. Now’s your chance to apply the ideas you read about. Find a partner and complete as much of the task below as you can. To receive credit for today’s lab, you must show your completed tasks to your instructor by the end of the day.
Your first task is to finish implementing the GitHubber app you started last time. Ensure that each team member has a local copy of the source directory. If you are using Live Share, collaborators can right-click on the shared folder and download it.
Your second task is to deploy your app to your droplet so that it’s available at https://githubber.YOUR-DOMAIN-NAME. You do this by running the following command in your React project:
npm run build
Notice that a new directory named build appears inside the top-level of your project. This folder must not be put in version control. It can be rebuilt at any time. In general, you should add this directory to your .gitignore file.
On your droplet, create a folder named githubber in your home directory, presumably right next to your project1 directory. Copy the files from your local build directory to your remote githubber directory. If you’re on a machine with Unix utilities, you can run the secure copy (scp) command:
scp -r build/* YOUR-DROPLET-IP-ADDRESS:githubber
If you don’t have scp, try WinSCP. Or something else. I don’t know Windows. As a last resort, you can clone your React project on your droplet and build it there.
Add an Apache virtual host for your app as you did in project 1. You’ll need to set permissions on the githubber directory and add a .conf file. Consult previous tutorial posts to remind yourself how this is done. Use HTTPS, and redirect HTTP traffic to HTTPS.
The next step of your learning is to complete the following tasks:
See you next time.
Dear students:
Welcome to lab. Now’s your chance to apply the ideas you read about. Find a partner and complete as much of the task below as you can. At the end of our time together, paste your files into Crowdsource in order to receive credit.
Your task is to write a React/Redux app that shows GitHub repositories matching a query. The matches will be provided by GitHub’s REST API. The end product will look something like this:

In the terminal, create a new React app and move into its directory:
npx create-react-app githubber cd githubber npm install redux react-redux redux-thunk
The next three sections can be done in parallel. Split them up between team members.
Create store.js as was done in the reading. Define a reducer that accepts the current state and an action and yields the new state. For the moment, the reducer should not do anything interesting. Whatever the action, return the unmodified state.
For initial testing, prime your state with a structure like this:
const initialState = {
matches: [
{
full_name: 'twodee/fiction',
description: 'This repository does not exist.',
html_url: 'https://github.com/twodee/fiction',
},
],
};
Define a store using the reducer, this initial state, and the thunk middleware.
In index.js, add a Provider component and pass your store as a prop.
Define a Repository component in Repository.js. It receives a prop named repository, which is an object shaped like the example from the initial state shown above, having keys full_name, description, and html_url. Display the repository’s full name in an anchor tag and the repository’s description.
Your next task is to reach into the global store and turn its matches array into viewable components. Complete the following steps in App.js.
useSelector hook to grab the matches from the store.Repository component. You should see the initial state showing twodee/fiction.Next add a search box so the user can query for real repositories. Follow these steps:
startSearching action (defined elsewhere).Now that you’ve got the initial state showing, it’s time to add some actions to pull down new state from GitHub’s REST API. Complete the following steps.
actions.js. It will have a structure similar to the ones from the readings.Action that acts as an enum. Give it an entry for LoadMatches.loadMatches that accepts an array of matches as a parameter. Have it return an object whose type is Action.LoadMatches and whose payload is the array of matches.startSearching that accepts a query string. It returns a lambda that accepts the dispatch function and fetches a list of repositories that match the query. Use the URL https://api.github.com/search/repositories?q=QUERY, replacing QUERY with the actual query string.loadMatches action, passing in the matching repositories.Action.LoadMatches. Return a new state whose matches property is the action’s payload.When the user types in a query and hits the button, the fetch will update the store and automatically re-render the app and display the matching repositories.
The next step of your learning is to complete the following tasks:
See you next time.
Dear students:
Welcome to lab. Now’s your chance to apply the ideas you read about. Find a partner and complete as much of the task below as you can. At the end of our time together, paste your files into Crowdsource in order to receive credit.
Your task in this lab is to finish up lab 19. Once that is working, modify your app so that the four pieces of state in the App component are in a global Redux store instead of passed around as props.
The next step of your learning is to complete the following tasks:
See you next time.
Dear students:
Welcome to lab. Now’s your chance to apply the ideas you read about. Find a partner and complete as much of the task below as you can. At the end of our time together, paste your files into Crowdsource in order to receive credit.
Your task in this lab is to create an app for curating a collection of images. To help classify the images and navigate the collection, the user can tag them. For example, an image of young people playing with a pet may be assigned the tags #kids and #dogs.
We will not use Redux for this lab.
The App component will hold all the shared state of your app. Declare these four pieces of shared state:
Set of tags (for example: new Set(['#dogs', '#kids'])){
fiveguys: {
id: 'fiveguys',
href: 'http://www.example.com/restaurants/burgers1.jpg',
tags: SET-OF-TAGS,
},
chickfila: {
id: 'chickfila',
href: 'http://www.example.com/restaurants/chicken3.jpg',
tags: SET-OF-TAGS,
},
// ...
}
The component has three children: Tags, Images, and Tagger.
The Tags component shows a unordered list of buttons, one for each tag. The tags are sent down via props. Clicking on a button changes the currently selected tag. The currently selected tag is state stored at the App level, so you will to use props to effect such a change.
The Images component shows a unordered list of buttons, one for each image that has the currently selected tag. The relevant images are sent down via props. Clicking on a button changes the currently selected image ID. The currently selected image ID is state stored at the App level, so you will need to use props to effect such a change.
Include a button for adding a new image by selecting the null image ID.
The Tagger component shows the following components for the currently selected image:
hrefidThe Tagger receives the image whose data is to be displayed via props. (If the ID is null, pass an object that creates an image with empty tags, href, and ID.) It uses the image’s properties to initialize three pieces of local state. To ease manipulation of the set of tags, turn the local version of the tag set into a space-separated string:
const [tags, setTags] = useState(Array.from(image.tags).join(' '));
When the user clicks the save button, the image is saved to the images object stored in App. You will need to use props to effect such a change. Bundle up the href, id, and tags string in an object and pass it along to a callback function.
In the callback, add the image into the object, replacing any image with the same ID. Split the tags up into its fields and add them to the larger set of tags. And deselect the image by nulling the current image ID.
See a reference callback function.
const saveImage = image => {
const imageTags = new Set(image.tags.split(/\s+/));
setImages({
...images,
[image.id]: {
id: image.id,
href: image.href,
tags: imageTags,
},
});
setTags(new Set([...tags, ...imageTags]));
setCurrentImageId(image.id);
};
The next step of your learning is to complete the following tasks:
See you next time.
Dear students:
Welcome to lab. Now’s your chance to apply the ideas you read about. Find a partner and complete as much of the task below as you can. At the end of our time together, paste your files into Crowdsource in order to receive credit.
Reverse engineer the following app using React:
Follow these guidelines in your solution:
App component and a new component named Row.Row component is responsible for a single row of the acrostic.App component is responsible for the theme input, the clear button, and a collection of Row instances.App manages a single piece of state: the theme of the acrostic.Make sure there are no errors in the console.
The next step of your learning is to complete the following tasks:
See you next time.
Dear students:
Welcome to lab. Now’s your chance to apply the ideas you read about. Find a partner and complete as much of the task below as you can. Actually, today’s lab is entirely optional. We’ll make it a workday for your project. But here’s an exercise in case you really want one.
Create a barebones client that uses the Follownet web service to do the following:
Use document.createElement to dynamically generate elements to which you can add event listeners.
The next step of your learning is to complete the following tasks:
report.html for project 2, document the endpoints that your service provides. Describe each endpoint’s purpose, HTTP method, path, parameters, any expected body content, and response.See you next time.