CS396: Spring 2022

Intro to Web Development

CS396: Spring 2022

Assignments > Lab 10. React

Due on Fri, 06/03 @ 11:59PM. 5 Points.

lab10.zip

Update

Sarah has created a series of video walkthroughs if it helps! Just to manage expectations: this is not professional quality, and I confuse myself in Video #3!

  1. Introduction
  2. Component Hierarchy
  3. NavBar & Posts Functionality (this one’s a little rough)
  4. Like / Unlike
  5. Getting Components to Notify One Another

Required Readings

Before beginning this week’s lab, please complete the React Step-by-Step Guide. It will take you and hour, but if you’re new to React it’s an hour well spent. It will be impossible for you to work effectively in React without understanding the core conventions and workflow, including:

Instructions

In this week’s lab, you will be re-implementing a subset of your Photo App UI using React. The following 5 tasks are required in order for you to get full credit for the lab:

  1. Create a component hierarchy
  2. Create stubs for each component
  3. Implement the “Posts” and “Post” components
  4. Implement the “LikeButton” component
  5. Implement the “BookmarkButton” component
  6. Fill out the accessibility questionnaire

Set Up

REST API

Your React client will rely on the REST API Endpoints you made in Homework 3 & 5. Therefore, you need to ensure that you’re running your flask application:

  1. Navigate to your photo-app directory.
  2. Activate your virtual environment
  3. Start the server: flask run

React Client

  1. Download lab10.zip, unzip it, and open the folder in VSCode.
  2. In another command line window/tab, navigate to the lab10 folder that you just created and install the required packages with npm install.
    • You will need to install npm if you haven’t already (see Lecture 19)
  3. Then, run the server locally using npm start

Tips

If you’re running into any errors with fetch requests, you may have a few minor bugs in your REST API Endpoint. To verify (Is the bug in my React code or in my API?), try running your code using the course API by updating your React app’s proxy url address in package.json to: https://photo-app-secured.herokuapp.com/.

Deployment Notes

Although we are using Node to build and run our React app, we will ultimately be compiling our React app to HTML, CSS, and JavaScript so that the browser can download these files from our website and run them client-side. It’s confusing, but the final output of our React App is client-side code that our browser will run.

Try building your React App by issuing npm run build on the command line. The resulting build folder will have “vanilla” HTML, CSS, and JavaScript that your browser understands.

Your Tasks

Step 1: Component Hierarchy

As described in the Thinking in React piece, it is important to be able to look at a wireframe / mockup and consider what might constitute a component (keeping in mind that components can have child components).

Given (a) the starter App.js file we have given you and (b) what you already know about the “Photo App” app you made in Homework 4, think about how you might break up this web app into different components, where each component does a small job within the larger application:

import React from 'react';

class App extends React.Component {  

    render () {
        return (
            <div>

            <nav className="main-nav">
                <h1>Photo App</h1>
                {/* Navigation Links */}
            </nav>

            <aside>
                <header>
                    Profile
                    {/* Navigation Links */}
                </header>
                <div className="suggestions">
                    <p className="suggestion-text">Suggestions for you</p>
                    <div>
                        Suggestions
                        {/* Suggestions */}
                    </div>
                </div>
            </aside>

            <main className="content">
                <header className="stories">
                    Stories
                    {/* Stories */}
                </header>
                <div id="posts">
                    Posts
                    {/* Posts */}
                </div>
            </main>

            </div>
        );
    }
}

export default App;

One potential strategy (though there could certainly be others) might involve splitting up your functionality into 5 top-level components, where each component has 1 job:

1. NavBar component Responsible for displaying the name of the logged in user, and perhaps a menu down the line.
2. Profile component Responsible for displaying a profile of the logged in user.
3. Suggestions component Responsible for displaying suggested users to follow.
4. Stories component Responsible for displaying recent stories of people you’re following.
5. Posts component Responsible for displaying the posts in your news feed.

Note that each of these top-level components may also have sub-components. For instance, Posts will probably be comprised of Post components, and each Post component will be comprised of, say, Comments, a LikeButton, a BookmarkButton, and potentially others. Here’s one way of visualizing this heirarchy:

Think about what your render() function might look like for each component, and which of your components might issue fetch requests.

Step 2: Create stubs for each component

Once you’ve decided on your components, create a JavaScript file for each of the 5 components listed above – NavBar, Profile, Suggestions, Stories, Posts – in your src directory. In each JavaScript file, create a react component and a simple render function that renders only the JSX elements associated with it. So, for instance, the Posts component would render a div element (and eventually the list of posts):

import React from 'react';

class Posts extends React.Component {
  
    constructor(props) {
        super(props);
        // initialization code here
    }

    componentDidMount() {
        // fetch posts and then set the state...
    }

     render () {
        if (!this.state.posts) {
            return (
                <div>Before posts fetched from server</div>  
            );
        }
        return (
            <div>
                <div>List of Posts goes here...</div>
                {/*
                this.state.posts.map(post => {
                    return <Post post={post} key={'post-' + post.id} />
                }
                */}
            </div>
        );     
    }
}

export default Posts;

When you’re done creating all of your components, refactor your App.js so that the render function is using your React components (don’t forget to import them all). Note that in the sample code shown below, the NavBar component is accepting two custom properties: “title” and “username.” Please review components and props if you have any questions about how that works.

import React from 'react';
import NavBar from './NavBar';
import Profile from './Profile';
import Stories from './Stories';
import Suggestions from './Suggestions';
import Posts from './Posts';

class App extends React.Component {  

    render () {
        return (
            <div>
                <NavBar title="Photo App" username="test_user" />
                
                <aside>
                    <Profile />
                    <Suggestions />
                </aside>

                <main className="content">
                    <Stories />
                    <Posts />
                </main>

            </div>
        );
    }
}

export default App;

If you get stuck, please take a look at hints/hint-1.

Step 3. Implement the “Posts” and “Post” Components

Next, modify the logic of your Posts component to display all of the posts in the news feed. Recall that in the React model, your fetch logic and your rendering logic are decoupled. In other words, you’ll probably want to:

Handling Authentication / Interaction with your REST API

Given that your Flask Server now requires your JWT token, we have created a helper function that will request and store an access token in your cookies before running your React app. See src/index.js for more information.

In order to issue requests with the required credentials, you will need to pass the JWT token in the header of your fetch requests. We have created a convenience function in the src/utils.js file called getHeaders(). See hints/hint-2 for an example of how to use this function.

On line 5 of package.json, is a “proxy server” instruction:

{
  "name": "photo-app-react",
  "version": "0.1.0",
  "homepage": "./",
  "proxy": "http://127.0.0.1:5000",
  "private": true
  ...
}

This instruction tells React that when you issue a request to, say, /api/posts, your request will be directed to use http://127.0.0.1:5000. If you prefer to interact with a different REST API server, just switch out the proxy address in package.json and re-run your react server. Feel free to use the class server if your HW5 is still in flux: https://photo-app-secured.herokuapp.com

Step 4. Implement the LikeButton Components

Recall from HW4 that when the user clicks the “like button,” a request is issued to the /api/posts/likes endpoint to either create or delete a like entry in the likes_posts table. This update causes a change to the post’s information (# of likes), which needs to be re-fetched from the server and re-displayed. In this exercise, you will create a brand new LikeButton component, whose job it will be to issue Like/Unlike requests to the server, and to draw the heart.

The LikeButton also needs to notify the Post component to redraw after it fetches data from the server. Therefore, you’re going to have to figure out how to communicate between your components. When you click on the heart in your LikeButton component, how can notify your Post component to requery the server and re-render? To learn how this might be done, re-read the lifting up state page, which provides guidance. The strategy discussed involves:

  1. Creating a method in the parent (Post) component to requery for the Post and set the Post component’s state.
  2. Making this method is available to the LikeButton component (by passing it in as a property).
  3. Ensuring that this method is called by the LikeButton component after the like/unlike functionality completes.

Step 5. Implement the BookmarkButton Component

Following the same strategy you used in Step 4, create a BookmarkButton component. This component’s job is to draw the bookmark icon, issue bookmark/unbookmark requests to the /api/bookmarks endpoint, and to notify the Post component that it needs to re-fetch and redraw the post.

Step 6. Accessibility

Accessibility Questionnaire

This quarter, we assigned a few accessibility activities – to encourage you to think about how people might interact with your applications without mouse or using a screen reader. To reflect on this process, please fill out the Accessibility Questionnaire.

Accessibility Research Study

We also wanted to invite you to participate in a research study – to examine and reflect on how to better teach students about accessibility within the software development process. Please fill out this Consent to participate in research form to let us know whether or not you are willing participate in this study. Participation is optional.

What to Turn In

When you’re done, zip your lab10 directory and submit your zip file to Canvas. Please DO NOT include your node_modules in the zip file (which will add hundreds of megabytes to your zip file).

Appreciations

And while you’re at it, please take a moment to thank / write a note to a peer mentor who helped you in some way (even if you just take 30 seconds to do it). Peer mentors are students too, and most of them do waaaay more than what is officially asked of them in order to support you. This form is completely anonymous.

https://forms.gle/zXdxaBik4suPifCA9