CSCI 344: Spring 2023

Advanced Web Technology

CSCI 344: Spring 2023

UNCA Logo

Assignments > Tutorial 8: Introduction to React

Due on Fri, 03/17 @ 11:59PM. 6 Points.

1. Do the Readings

If you haven’t yet taken a look at these documents, carve out some time to do it. They’re important.

2. Set Up Instructions

tutorial08.zip

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.

A few things to notice

Before you start coding, please take a look at the following:

1. Proxy URL

package.json is a configuration file used by Node.js. It specifies rules for which packages dependencies should be installed (read via the npm install). It also has some speficications for how the application should behave. One of these is a property called proxy, which is set to https://photo-app-secured.herokuapp.com/. What this means is that in each of your fetch endpoints, you don’t need to specify the fully qualified path. For instance, if you want to query for a list of Post objects, you only need to specify this address: /api/posts.

2. public/index.html

Your base HTML file is located in the public folder. Take a look at it, noting how simple it is:

<!doctype html>
<html lang="en">
<head>
    <title>Photo App</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css">
</head>
<body>
    <div id="root"></div>

</body>
</html>

3. src/index.js

src/index.js “kicks off” your web app. Ope it and take a look at it. Note that the renderApp() function is invoked at the bottom. The function first authenticates to the https://photo-app-secured.herokuapp.com/ server with the webdev/password (you should switch this to your username and password). Then, it passes the authentication token as an argument to the <App /> component. This component is then added to the DOM (located in the public/index.html file) within #root DOM element.

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';
import {getAccessToken} from './utils';

// Kicks off the app after the user "logs in":
async function renderApp() {
    const token = await getAccessToken('webdev', 'password');
    
    ReactDOM.render(
        <App token={token} />,
        document.getElementById('root')
    );
}

renderApp();

3. src/App.js

src/App.js is your top-level React component. Open it and take a look at it. You should see a structure like the one shown below. Your first and second tasks are to create components for each of the data-generated sections of your app (we will walk through this process together).

import React from 'react';
import NavLinks from './NavLinks';

export default function App ({token}) { 
    console.log('access token:', token);
    
    return (
        <div>
            
            {/* Navbar */}
            <nav className="main-nav">
                <h1>Photo App</h1>
                <NavLinks token={token} />
            </nav>
           
           {/* Right Panel */}
            <aside>
                <header>
                    Profile Goes Here...
                </header>
                <div className="suggestions">
                    <div>
                        Suggestions go here...
                    </div>
                </div>
            </aside>

            <main>

                {/* Stories */}
                <header className="stories">
                    Stories go here...
                </header>

                {/* Posts */}
                <div id="posts">
                    Posts go here...
                </div>

            </main>

        </div>
    );
    
}

3. Your Tasks

In this week’s tutorial, you will begin HW6 (re-implementing the Photo App UI using React). To get full credit for this tutorial, complete the following tasks:

  1. Create a component hierarchy (we will walk through this together)
  2. Create stubs for each component
  3. Implement the “Posts” and “Post” components
  4. Implement the “LikeButton” component

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 & 5, think about how you might break up this web app into different components, where each component does a small job within the larger application. 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. NavLinks component (Already done for you) 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 5 top-level components may also have sub-components. For instance:

Some questions you should be asking yourself:

Also, You are strongly encourageed to add a comment at the top of each component that is a 1-sentence summary of what the component’s “job” is (which is good software engineering practice).

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 – NavLinks (already done for you), Profile, Suggestions, Stories, Posts – in your src directory. To begin with, each React component should just return the simplest JSX representation of the component that you can think of (given that we’re not querying the API yet). We will make our components “smarter” later on. So, for instance, the Posts component could render a simple div element (but would eventually render a list of posts):

import React from 'react';

export default function Posts() { 
   
    return (
        <div>Your posts here...</div>
    ); 

}

When you’re done creating all of your components, refactor your App.js to use the 5 React components you just made (don’t forget to import them all).

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

export default function App ({token}) { 
    console.log('access token:', token);
    
    return (
        <div>
            {/* Navbar */}
            <nav className="main-nav">
                <h1>Photo App</h1>
                <NavLinks token={token} />
            </nav>
            
            <aside>
                <Profile />
                <Suggestions />
            </aside>

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

        </div>
    );
}

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:

Suggested References

If you get stuck, look at the hints folder and study the Post.js structure. Don’t just copy it…look at it and try to understand what’s happening.

Step 4. Implement the LikeButton Component

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 corresponding database table. Because this update causes a change to the post’s information (# of likes), it 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 do this, you will be doing something called “lifting up state.” The strategy discussed involves:

  1. Creating a function in the parent (Post) component to requery for the Post and set the Post component’s state.
  2. Making this function 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.

What to Turn In

When you’re done, zip your tutorial08 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).