The React Router supports SPAs with multi-page and nested-page structures.

Adding a New Page to the Comments Application

If necessary, finish the React Router tutorial as specified in the guide and review the guide questions.

Exercise 13.1

Make a copy of your solution for the previous lab and store it under lab13. Remember to ensure that you copy .gitignore. Note that as with previous labs, some of the configuration in this lab is version-dependent so we suggest that you integrate the package.json file provided in the course repo for lab 13.

Now, refactor the application to use React Routing as follows.

  1. You can skip this step if you’ve integrated the new lab 13 package.json file discussed above. If still necessary, install the React Router library using the Node Package Manager (npm).

    npm install react-router --save
  2. Import Router, Route and browserHistory from React-Router into index.js.

    import { Router, Route, browserHistory } from 'react-router';
  3. Because we’re using browser history, be sure to modify the server appropriately.

    • For the development server, see the modifications to Webpack Dev Server in the tutorial, lesson 10.
    • For the production server, add/update the following statements in your server (server.js) as appropriate.
      // Add this at the top, just after the imports.
      var APP_PATH = path.join(__dirname, 'dist');
      
      // Modify the current app.use() command.
      app.use('/', express.static(APP_PATH));
      
      // Add this at the bottom, just before starting the server.
      app.use('*', express.static(APP_PATH));
      These statements add an application-path variable and then update the server to: (1) map the main app to that path; and (2) add a catch-all route handler that sends non-root requests to that path.
  4. Refactor index.js to use the React Router to map the / route to the CommentBox component.

    ReactDOM.render((
            <Router history={browserHistory}>
                <Route path="/" component={CommentBox}/>
            </Router>
        ), document.getElementById('content')
    );

    We won’t include any home page or menu bars, as demonstrated in the React Router tutorial, just this one route for this exercise.)

  5. Refactor the app so that the API URL and poll interval values, currently hard-coded in index.js, are implemented as constants defined in a global.js module.

    const API_URL = 'api/comments';
    const POLL_INTERVAL = 2000;
    
    module.exports = { API_URL, POLL_INTERVAL };

    Import this new global.js module into CommentBox.js and use the constants as appropriate. (Nb. This isn’t what the Facebook tutorial did with these values, but React Router doesn’t provide obvious support for parameter passage and it makes some sense to use this approach anyway. An alternative would be to use query-string parameters.)

The development and production servers should still operate as they did before. When you’ve confirmed this, consider the following.

  1. What benefit did using the React Router bring to the application?
  2. Which is better, hash history or browser history?
  3. Why does the server (either Webpack Dev Server or the Express server) have to be modified to support the browser history? Compare this with the hash-based server demonstrated in class, which didn't require such modifications.

Save summaries of your answers to these questions in a lab13.txt file in the root of your lab repo.

You can compare your solution with the one in the course repo.

Adding an Edit/Delete Comment Feature

We now add a new “page” to the application that supports editing and deleting comments.

Exercise 13.2

Add a new comment-editing/deleting page as follows.

  1. Define a new CommentEdit component in commentEdit.js that allows the user to edit and/or delete a given comment. You can find basic code for this component here: commentEdit.js. Familiarize yourself with the component, noting that it imports/uses the API_URL constant defined above and being clear on what state it maintains, what data it loads, and what the form it renders allows the user to do (nb. keep track of your answers for use below).

  2. Upgrade your Express server to support GET, PUT and DELETE on the /api/comment/:id route. You can find functions to do this here: server.js.

  3. Update commentBox.js so that the calls to loadCommentsFromServer() stop updating the state when the commentEdit component is mounted rather than the commentBox component. You can find edits for this here: commentBox.js (see the three updates that integrate the state flag _isMounted).

  4. Add a new route for CommentEdit in index.js, passing the ID of the comment to be edited as a URL parameter.

    <Route path="/:id" component={CommentEdit} />
  5. The CommentEdit component needs the unique ID of the comment, but the key parameter currently being passed to the Comment component (in commentList.js) is inaccesible. Add an id property in commentList.js.

    <Comment id={comment.id} author={comment.author} key={comment.id}>
  6. Add an “Edit” link from the Comment component defined in comment.js to the new CommentEdit component.

    <Link to={'/' + this.props.id}>Edit</Link>

The development version of the application should now support the edit/delete feature (nb. we’ll reconfigure the production deployment in the next exercise).

  1. What state does the new CommentEdit component maintain and how does that compare with the state maintained by the CommentBox component?
  2. What does the CommentEdit component do when the AJAX PUT or DELETE methods return successfully? How does this compare with what the “Cancel” button provided by the CommentEdit component does?
  3. How is the Link added in the last step different from a simple HTML hyperlink?

Save summaries of your answers to these questions in your lab13.txt file.

You can compare your solution with the one in the course repo. The Heroku deployment should still work, with a couple adjustments.

Exercise 13.3

You can deploy this new version of the application to Heroku as you did in the previous lab with the following modifications.

  1. Create and push a new production branch for this lab (production13) to GitHub. This will allow you to distinguish it from the last unit’s version and access both as needed.

  2. Reconfigure your Heroku application to deploy from the new branch production13. If you haven't configured auto-deploy, instruct Heroku to manually (re)deploy this new branch.

Verify that your new production system is running on Heroku.

Please include the URL of your Heroku deployment (probably the same as it was in the previous lab) in your lab13.txt file.

Compare your solution with the sample application running here: https://comments-kvlinden.herokuapp.com/

Checking in

We will grade your work according to the following criteria: