In this chapter, we will elaborate on some of the best practices to apply when building the six MERN applications in this book. Additionally, we will explore other practices that we have not applied in this book but that should be considered for real-world applications to ensure reliability and scalability as complexity grows. We will review the decisions behind organizing the project code in modules, the approaches to applying frontend styling, server-side rendering with data only for selective views, and how React interfaces may be composed to manage state across components. We will also look at ways to improve security, add testing to the projects, and optimize bundling with webpack. Finally, we will wrap up with suggestions for enhancing, and steps for extending, the applications built. With these insights, you will be better...
You're reading from Full-Stack React Projects. - Second Edition
Separation of concerns with modularity
While building the MERN stack applications in this book, we followed a common folder structure across each application. We employed a modular approach by dividing and grouping the code based on relevance and common functionality. The idea behind creating these smaller and distinct sections in the code is to make sure each section addresses a separate concern, so individual sections can be reused, as well as developed and updated independently. In the following section, we will review this structure and its benefits.
Revisiting the application folder structure
In the application folder structure, we kept the client-side and server-side code separate with further subdivisions within these...
Adding CSS styles
When discussing user interface (UI) implementations for the applications in this book, we chose not to focus on the details of the CSS styling code applied and instead relied mostly on the default Material-UI stylings. However, given that implementing any UI requires us to consider styling solutions, we will briefly look at some of the options that are available.
When it comes to adding CSS styles to the frontend, there are a number of options, each with pros and cons. In the following sections, we will discuss the two most common options, which are external style sheets and inline styles, along with the relatively newer approach of writing CSS in JavaScript, or, more specifically, JSS, which is used in Material-UI components and hence also for the applications in this book.
Selective server-side rendering with data
When we developed the frontend of the base skeleton application in Chapter 4, Adding a React Frontend to Complete MERN, we integrated basic server-side rendering in order to load client-side routes directly from the browser address bar when the request went to the server. In this server-side rendering implementation, while rendering the React component's server-side, we did not consider loading the data from the database for the components that displayed data. The data only loads in these components when the client-side JavaScript takes over after the initial load of the server side-rendered markup.
We did update this implementation to add server-side rendering with data for the individual media detail pages in the MERN Mediastream application, which was discussed in Chapter 12, Customizing the Media Player and Improving the SEO....
Using stateful versus pure functional components
While building a UI with React components, composing the views with more stateless functional components can make the frontend code manageable, clean, and easier to test. However, some components will require the state or life cycle Hooks to be more than pure presentational components. In the following sections, we will look at what it takes to build stateful and stateless functional React components, when to use one or the other, and how often.
Stateful React components with ES6 classes or Hooks
We can define stateful React components with ES6 classes or by using Hooks without writing a class. React components defined using ES6 classes have access to life cycle methods, the...
Using Redux or Flux
When React applications begin to grow and become more complex, managing communication between components can become problematic. When using regular React, the way to communicate is to pass down values and callback functions as props to the child components. However, this can be tedious if there are a lot of intermediary components that the callback must pass through. To address these state communication and management-related issues as the React application grows, people turn to use React with libraries and architecture patterns such as Redux and Flux.
It is outside the scope of this book to delve into the details of integrating React with the Redux library or the Flux architecture, but you can consider these options for their growing MERN applications while keeping the following in mind:
- Redux and Flux utilize patterns that enforce changing states in a React...
Enhancing security
In the MERN applications developed for this book, we kept the auth-related security implementations simple by using JSON web tokens (JWTs) as an authentication mechanism and by storing hashed passwords in the user collection. The approaches followed in these implementations are standard practices for adding authentication to a web application. However, there are advanced options available for adding more layers of security, if that is required for certain applications. In the following sections, we will go over the security choices made for building the applications in this book and point to possible enhancements.
JSON web tokens – client-side or server-side storage
With the JWT authentication mechanism...
Writing test code
Though discussing and writing test code is outside the scope of this book, it is a crucial part of developing reliable software. As full-stack JavaScript applications become more mainstream over time, the need for better testing capabilities is producing a good number of testing tools in this ecosystem. In the following sections, we will first look at some of the popular testing tools that are available for testing the different parts of a MERN-based application. Then, to help you get started with writing test code for the MERN applications developed in this book, we will also discuss an example of adding a client-side test to the MERN Social application from Chapter 5, Growing the Skeleton into a Social Media Application.
Testing tools for full-stack JavaScript projects...
Optimizing the bundle size
As you develop and grow a MERN application, chances are the size of the bundles produced with webpack will also grow, especially if large third-party libraries are used. Larger bundle sizes will affect performance and increase the initial load time of the application. We can make changes in the code to ensure we don't end up with large bundles and also utilize features packed in webpack to help optimize bundling.
Extending the applications
Throughout the chapters of this book, as we developed each application, we added features by extending the existing code in a common and repeatable number of steps. In this final section, we will review those steps, setting a guideline for adding more features to the current versions of the applications.
Extending the server code
For a specific feature that will require data persistence and APIs to allow the views to manipulate the data, we can start by extending the server code and adding the necessary models, routes, and controller functions, as outlined in the following sections.
Adding a model
...Summary
In this final chapter, we reviewed and elaborated on some of the best practices that we used while building the MERN applications in this book, highlighted areas of improvement, gave pointers to address issues that may crop up when applications grow, and, finally, set down steps to continue developing more features into the existing applications.
We saw that modularizing the application's code structure helped to extend the application easily, choosing to use JSS over inline CSS and external style sheets kept the styling code contained and easy to work with, and only implementing server-side rendering for specific views as required kept unnecessary complications out of the code.
We discussed the benefits of creating fewer stateful components that are composed of smaller and more defined stateless functional components, and how this can be applied while refactoring...