Skip to content

Complementary front-end for the backend API created in exercise #192 #204

@imwirelesscloud

Description

@imwirelesscloud

Complementary front-end for the backend API created in exercise #192

We'll use Redux Thunk for asynchronous actions and React Router for routing, just without using the deprecated Switch component. Let's get started.


Implementation Guidelines

Part 1: Initialize the React App

Step 1: Create a New React App

Open your terminal, navigate to the directory where you want to store your project, and run the following command to create a new React app:

npx create-react-app bookstore-frontend

Rationale:

The create-react-app command sets up a new React project with good default settings. It includes a build process that makes your modern React code compatible with older browsers.

Part 2: Folder Structure and Installing Dependencies

Step 2: Folder Structure

Your React app comes with a certain folder structure. To better organize your code, create folders within the src directory named components, actions, reducers, contexts, and models.

Rationale:

Creating these folders is not required but helps keep your code organized as your project scales.

Step 3: Install Dependencies

We'll need Axios for API calls, Redux and Redux Thunk for state management, and React Router for routing. Run the following command to install these packages:

npm install axios react-redux redux redux-thunk react-router-dom

Rationale:

  • Axios is used for making API calls.
  • React-Redux and Redux are used for state management.
  • Redux Thunk is used for asynchronous actions in Redux.
  • React Router Dom is used for client-side routing.

Part 3: Set Up Routing

Step 4: Basic Routing

Open src/App.js and replace its content with:

import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import HomePage from './components/HomePage';
import BookPage from './components/BookPage';
import LoginPage from './components/LoginPage';

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<HomePage />} />
        <Route path="/book/:id" element={<BookPage />} />
        <Route path="/login" element={<LoginPage />} />
      </Routes>
    </Router>
  );
}

export default App;

Rationale:

We've used the Routes and Route components to set up routing. Each Route component has a path prop to specify the URL pattern and an element prop to specify what component should be rendered.

Part 4: Components, State Management, and API Calls

This part will cover creating React components, setting up Redux for state management, and making API calls. It would be too long to outline all of that here, but the pattern would involve:

  1. Creating a React component.
  2. Writing actions and reducers to manage the state related to that component.
  3. Using Axios to make API calls in the actions.
  4. Using Redux Thunk to handle asynchronous logic.
  5. Dispatching actions from the components to fetch, create, update, or delete books.
  6. Showing that data on the web page by fetching it from the Redux store.

Rationale:

  • Components divide the UI into reusable pieces.
  • Redux manages the state in one centralized store, making it easier to debug and manage.
  • Axios makes API calls to fetch or manipulate data.
  • Redux Thunk allows you to write action creators that return a function instead of an action.

Part 5: Authentication and Authorization

  1. Create a Login component.
  2. Make an API call to authenticate the user.
  3. Store the JWT token in the Redux store and local storage.
  4. Use React Router's useNavigate and the token to conditionally redirect the user to different routes based on their authentication and authorization status.

Rationale:

  • Storing the JWT token allows for secure and stateless authentication and authorization.
  • React Router’s useNavigate allows for programmatic navigation, enabling the user to be redirected after actions like successful login or logout.

This provides a skeleton of how to approach your React frontend project for your bookstore. It uses Redux for state management, Axios for API calls, and React Router for routing, without using the deprecated Switch. I hope this makes your development process clearer and more organized.


Explanation of Concepts Used

Creating a full-fledged guide explaining every concept in detail would be a monumental task, but I'll give you a detailed overview of the core concepts, dependencies, and security measures involved in the outlined frontend application for an online bookstore.

Dependencies

React

What is it?
React is a JavaScript library for building user interfaces. It allows you to construct complex UIs from small and isolated pieces of code called "components."

Why use it?
React's virtual DOM optimizes rendering and improves performance. JSX (JavaScript XML) simplifies the creation of UI components.

React-Redux

What is it?
React-Redux is the official React binding for Redux. It allows your React components to read data from the Redux store and dispatch actions to the store to update data.

Why use it?
It simplifies managing the state in React applications. It also allows for better debugging and a clearer structure.

Redux

What is it?
Redux is a state management library. It centralizes an application's state and logic.

Why use it?
It helps you manage the state of your application more efficiently and predictably, especially for large applications.

Redux Thunk

What is it?
Redux Thunk is a middleware that allows you to write action creators that return a function instead of an action object.

Why use it?
Thunks allow for delayed actions, including working with promises. This is beneficial for any kind of asynchronous logic.

Axios

What is it?
Axios is a promise-based HTTP client for JavaScript, often used for front-end and Node.js back-end applications.

Why use it?
Axios allows you to make HTTP requests to external resources. It is promise-based, making it easier to handle asynchronous operations.

React Router

What is it?
React Router is a standard routing library for React, to navigate between different components.

Why use it?
Routing is essential for any single-page application (SPA). React Router gives you the tools to move seamlessly between components without reloading the page.

Web Development Concepts

Component-Based Architecture

In React, the UI is divided into components, each responsible for rendering a UI part.

State Management

React provides a useState hook for local state management within components. For global state management, Redux is commonly used.

API Calls

HTTP requests allow the front-end to communicate with the back-end. In this context, Axios is used for API calls to the Express.js backend.

Routing

Routing allows navigation between different parts of an application. In a single-page application, client-side routing is handled through React Router.

Asynchronous Programming

Promises and async/await are crucial in handling API responses, performed asynchronously. Redux Thunk helps in this regard.

Security Concepts

JWT for Authentication

JSON Web Tokens (JWT) are an open, industry standard (RFC 7519) for representing claims between two parties.

HTTPS

Always make sure that your application is served over HTTPS, especially when dealing with JWT.

Local Storage

Storing JWT tokens in local storage can be risky due to potential cross-site scripting (XSS) attacks. Alternatives like HttpOnly cookies can be more secure.

Authorization

Once authenticated, you can limit what resources the user can access using their role, a technique known as Role-Based Access Control (RBAC).

Development Process

  1. Requirements Analysis: Understand what the application is supposed to do.
  2. Design Architecture: Decide on the file structure, state management strategy, and routing.
  3. Develop Components: Develop individual UI components.
  4. Integrate Backend: Use Axios to make API calls for CRUD operations.
  5. State Management: Use Redux to manage the application state.
  6. Routing: Implement client-side routing using React Router.
  7. Testing: Write unit and integration tests to make sure everything works as expected.
  8. Deployment: Once everything is tested, the final step is to deploy your application.

This is a high-level overview, but I hope it provides a strong foundation and understanding of how to develop a secure, efficient, and scalable React frontend application for an online bookstore.


Deeper-dive

Creating a fully-detailed guide like an explainer book would be extensive. I'll provide a skeleton for each topic and go into some detail to give you an idea.

Frontend Instructions and Guidelines

Step 1: Initial Setup

Instructions

  1. Create a new React app using Create React App:

    npx create-react-app online-bookstore
  2. Navigate to the project folder:

    cd online-bookstore
  3. Install the required dependencies:

    npm install react-redux redux axios react-router-dom

Guidelines

  • Create React App: This is a CLI tool to bootstrap a new React application. It sets up a new project with sensible defaults and best practices.

Step 2: Folder Structure

Instructions

  1. Create the following folders inside src/:
    - components
    - pages
    - services
    - store
    

Guidelines

  • components: For reusable UI elements like Header, Footer, etc.
  • pages: For components serving as different routes/pages in your application.
  • services: For business logic like API calls.
  • store: For Redux state management setup.

Step 3: Redux Setup

Instructions

  1. Inside store/, create files actions.js, reducers.js, and store.js.

Guidelines

  • actions.js: Will contain all Redux action creators.
  • reducers.js: Will contain all Redux reducers to handle state changes.
  • store.js: Will set up the Redux store and integrate middleware like Redux Thunk.

Step 4: Implement Routing

Instructions

  1. Inside App.js, implement basic routing using react-router-dom.
import React from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import HomePage from './pages/HomePage';
import BookPage from './pages/BookPage';

function App() {
  return (
    <Router>
      <Route path="/" exact component={HomePage} />
      <Route path="/book/:id" component={BookPage} />
    </Router>
  );
}

export default App;

Guidelines

  • BrowserRouter: Wraps the application and makes it routing-aware.
  • Route: Defines paths and maps them to specific components.

Step 5: API Calls & Redux Thunk

Instructions

  1. Inside services/, create a file called api.js.
  2. Use Axios to perform API calls.

Guidelines

  • Axios: Axios is a popular library to make HTTP requests. It supports promises by default, making it easier to manage asynchronous operations.

Example

// services/api.js

import axios from 'axios';

export const fetchBooks = async () => {
  const response = await axios.get('/api/books');
  return response.data;
};

Step 6: Create Components

Instructions

  1. Create reusable UI components under the components/ folder.

Guidelines

  • Component Structure: Try to make your components as reusable as possible.

Example

// components/Header.js

const Header = () => {
  return (
    <header>
      <h1>Online Bookstore</h1>
    </header>
  );
};

export default Header;

Step 7: State Management with Redux

Instructions

  1. Use Redux for managing the state of books and user info.
  2. Create actions and reducers for fetching books from the API and storing them in the Redux state.

Guidelines

  • State Management: Redux will be used to manage the state of the application at a global level.

Step 8: Security Measures

Instructions

  1. Store JWT tokens securely.
  2. Implement role-based redirects.

Guidelines

  • JWT: Should be stored in a more secure way, either in HttpOnly cookies or in-memory storage to prevent XSS attacks.
  • Role-based: Use Redux to check the role of the user and redirect accordingly.

Step 9: Testing

Instructions

  1. Use Jest and the React Testing Library for component and functionality testing.

Guidelines

  • Unit Testing: Each component should have its unit tests to ensure it renders correctly.

Step 10: Deployment

Instructions

  1. Build your project:

    npm run build
  2. Deploy to a server or a hosting platform like Netlify or Vercel.

Guidelines

  • Environment Variables: Ensure all environment variables are set correctly.
  • HTTPS: Make sure to enable HTTPS for security reasons.

That's a high-level overview. Each section can be expanded into multiple pages with examples, tips, and best practices. It would be equivalent to a book chapter, but I hope this gets you started and serves as a useful guide.


Certainly, let's continue our deep dive into the frontend instructions and guidelines.

Step 11: Client-Side Security

Instructions

  1. Add input validation checks on all forms.
  2. Use HTTPS for all API calls.

Guidelines

  • Input Validation: Always validate user input to ensure that only properly formed data is entering the workflow.

    Example:

    // Inside a form component
    if (username.length < 5) {
      setError('Username must be at least 5 characters long');
    }
  • HTTPS: Make sure all API calls use HTTPS to encrypt data during transmission.

Step 12: User Authentication and Authorization

Instructions

  1. Create a login and register component.
  2. Use JWT tokens for authentication.
  3. Implement role-based access for routes.

Guidelines

  • JWT: JSON Web Tokens (JWT) are used for securely transmitting information between parties as a JSON object.

    Example:

    // services/authService.js
    export const authenticateUser = async (credentials) => {
      const { data: jwt } = await axios.post('/api/auth', credentials);
      localStorage.setItem('token', jwt);
    };
  • Role-based Authorization: After decoding the JWT, you can determine the user role and then decide whether a user is authorized to access a resource.

    Example:

    // Inside a Route guard component
    if (userRole !== 'admin') {
      return <Redirect to="/" />;
    }

Step 13: Error Handling

Instructions

  1. Implement a global error-handling mechanism using React Error Boundaries.

Guidelines

  • Error Boundaries: Error boundaries are React components that catch JavaScript errors anywhere in their child component tree.

    Example:

    // components/ErrorBoundary.js
    class ErrorBoundary extends React.Component {
      state = { hasError: false };
      static getDerivedStateFromError() {
        return { hasError: true };
      }
      render() {
        if (this.state.hasError) {
          return <h1>Something went wrong.</h1>;
        }
        return this.props.children;
      }
    }

Step 14: Accessibility

Instructions

  1. Make sure all images have alt attributes.
  2. Use semantic HTML tags.

Guidelines

  • Accessibility: Building accessible websites is a best practice that benefits everyone, not only those with disabilities.

    Example:

    <img src="/path/to/image" alt="Book cover of XYZ" />

Step 15: Responsiveness

Instructions

  1. Use CSS Flexbox or Grid to make the app responsive.

Guidelines

  • Flexbox/Grid: These are modern layouts for CSS. They provide an easier and cleaner tool for setting up layouts.

    Example:

    /* Using Flexbox */
    .container {
      display: flex;
      justify-content: space-between;
    }

Step 16: Code Review and Refactoring

Instructions

  1. Review your code for any anti-patterns, unnecessary parts, or possibilities for improvements.

Guidelines

  • Code Review: This process is crucial for maintaining the codebase and ensuring that best practices have been followed.

Step 17: Documentation

Instructions

  1. Document your code adequately for better maintainability.
  2. Update the README.md file to include setup instructions and basic documentation.

Guidelines

  • Documentation: Good code should explain what it does, but complex logic or workarounds should always be documented.

Step 18: Final Testing

Instructions

  1. Perform full regression testing.
  2. Test on different browsers.

Guidelines

  • Testing: Final round of testing is essential to make sure everything is working as expected.

Step 19: Deployment

Instructions

  1. Optimize code splitting and lazy loading.
  2. Deploy to your favorite cloud provider.

Guidelines

  • Code Splitting: This is a feature offered by bundlers like Webpack, which can create multiple bundles that can be dynamically loaded at runtime.

    Example:

    // Using React.lazy to lazy-load a component
    const OtherComponent = React.lazy(() => import('./OtherComponent'));
  • Cloud Provider: AWS, Azure, Google Cloud, or other cloud providers can host your web application. Some platforms like Vercel and Netlify are more straightforward for frontend apps.

And there you have it, a comprehensive guide for setting up, developing, and deploying a frontend React application. These guidelines can serve as chapters in an explainer book and could be expanded upon further.

Originally posted by @akash-coded in #193

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions