Fullstack React - Chapter 3 Notes

Summary

This post contains notes from chapter 3 in Fullstack React - "Components & Servers". The purpose of this chapter is to learn how to send data back up to the server.

Overview 


  • curl - command line tool for making web requests. I like to use the Chrome extension RestEasy.
  • You want to keep state in both the server and in the client app. I think this depends on the application. In the case of a timer, there is an obvious lag that ruins the user experience because we were building a timer. In a more traditional app, it may not be as necessary to update state in both places. There is a lot of extra complexity in doing so, like making the same checks that would occur on the server so you stay in sync with what happened on the server. For example, if the server has a check that throws an error if a property is null, then we would want to code that same check on the client side.
  • server.js summary
    • server.js is the file that handles incoming requests and routes them accordingly. For example, if we hit our url http://localhost:3000, then server.js sees this and returns index.html as the response.
    • React only makes calls to the server when interacting with the API endpoints, so React would never call server.js directly
  • When loading state from a server, you still want to declare the initial state of your objects so the components can render. The initial state would just contain empty objects. In the following example the initial state contains an empty array to store the list of movies. Note, in the book, we work with timers, but I wanted to try my own thing, so I made an example for showing a list of movies instead.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    class MovieList extends React.Component {
        state = {
            movies: [
            ]
        };
    
        render () {
            const movieComponents = this.state.movies.map((movie) => (
                <Movie 
                    key={movie.id} 
                    title={movie.title} 
                    id={movie.id}  
                />
            ));
    
            return (
                <ul>
                    {movieComponents}
                </ul>
            );
        }
    }
    

  • After the initial state is loaded and the DOM is rendered, componentDidMount will fire and then we can make a call to the server to get our list of movies
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    class MovieList extends React.Component {
        state = {
            movies: [
            ]
        };
    
        componentDidMount = () => {
            this.loadMoviesFromServer();
        };
    
        loadMoviesFromServer = () => {
            client.getMovies((serverMovies) => (
                this.setState({ movies: serverMovies })
            ));
        };
    
        render () {
            const movieComponents = this.state.movies.map((movie) => (
                <Movie 
                    key={movie.id} 
                    title={movie.title} 
                    id={movie.id}  
                />
            ));
    
            return (
                <ul>
                    {movieComponents}
                </ul>
            );
        }
    }
    

  • client.js - This is a helper file that makes the calls to the server to read and write movies. In a real application, I assume this would be broken up into a more formal pattern, like a moviesService or something like that.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    window.client = (function () {
      function getMovies(success) {
        return fetch('/api/movies', {
          headers: {
            Accept: 'application/json',
          },
        }).then(checkStatus)
          .then(parseJSON)
          .then(success);
      }
    
      function createMovie(data) {
        return fetch('/api/movies', {
          method: 'post',
          body: JSON.stringify(data),
          headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
          },
        }).then(checkStatus);
      }
    
      function updateMovie(data) {
        return fetch('/api/movies', {
          method: 'put',
          body: JSON.stringify(data),
          headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
          },
        }).then(checkStatus);
      }
    
      function deleteMovie(data) {
        return fetch('/api/movies', {
          method: 'delete',
          body: JSON.stringify(data),
          headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
          },
        }).then(checkStatus);
      }
    
      function checkStatus(response) {
        if (response.status >= 200 && response.status < 300) {
          return response;
        } else {
          const error = new Error(`HTTP Error ${response.statusText}`);
          error.status = response.statusText;
          error.response = response;
          console.log(error);
          throw error;
        }
      }
    
      function parseJSON(response) {
        return response.json();
      }
    
      return {
        getMovies,
        createMovie,
        updateMovie,
        deleteMovie
      };
    }());
    

  • Fetch API
    • Fetch is a library that we can use to perform our ajax calls up to the server
    • Fetch is quickly being adopted and looks to be on its way to becoming the standard way for making web requests. It is still being standardized and hasn't been adopted by all major browsers, but it looks like it is on its way.
    • For now, we just have to include the library (my guess is via an npm install, but the book did note that it is supported by a few major browsers.
    • Add notes about what happens during a Fetch call including notes about how it uses promises
    • fetch has 2 parameters:
      • path - the url that we are making the request to
      • request object - the object that defines the contents of the request
        • method - this can be any standard type of http request, defaults to GET
        • body - the body of the request (typically will be json for me)
        • headers - defines the header of the request, like content-type of the request or the type of content we accept
    • fetch returns a promise, which is useful so we can chain function calls together.
      • In the getMovies function above, the following order of events will happen
        • fetch is triggered and makes the web request
        • After fetch is completed and the request returns, checkStatus is called and the results of fetch (the response from the web request) is passed in as a parameter to checkStatus
        • After checkStatus is completed, its results (again the response) is passed to parseJSON
        • After parseJSON is completed, its results (this time the javascript object, which will be the array of movies) is passed to the callback function that was passed in via the success variable and the success callback function is invoked
  • Optimistic updating (Page 129 - 130)
    • Optimistic updating is the practice of assuming the request to the server finished successfully, so we update the local state without waiting for the response from the server with what we expected to have happened on the server. For example, if we were adding a new movie, we would add that movie to the local state so it could appear in our list of movies before the the request to the server finishes. We would need to add some logic in to handle error conditions, but the book didn't really go through that at this point. I am hoping they cover that in a later chapter.
  • The book covers all of the different CRUD operations and how they are made to the web server. I created CRUD Operations in React - Server State to cover that, so I am not going to repeat all of those details in this post.

No comments:

Post a Comment

} else { }