Janek Kruczkowski

A Comprehensive Case Study: Building a Masking Email System with React.js and Best Practices

Introduction

Email masking is an essential practice to protect users' privacy and prevent spam. In this article, we'll explore how to build a masking email system using * React.js* and best practices. React.js is a popular JavaScript library for building user interfaces, and its component-based approach makes it ideal for creating scalable applications.

Setting up the project

Prerequisites

Before starting, make sure you have the following installed:

  • Node.js (version 12.x or higher)
  • npm (version 6.x or higher)

Initializing the project

To create a new React.js project, run the following command in your terminal:

npx create-react-app masking-email-app

Creating the frontend

Designing the form

Create a new component called EmailForm and include the following code:

import React from 'react';

function EmailForm() {
    return (
        <form>
            <label htmlFor="email">Enter your email:</label>
            <input type="email" id="email" required/>
            <button type="submit">Mask My Email</button>
        </form>
    );
}

export default EmailForm;

Handling form submission

Add an onSubmit event handler to the form and a state variable to store the email input:

import React, {useState} from 'react';

function EmailForm() {
    const [email, setEmail] = useState('');

    const handleSubmit = (event) => {
        event.preventDefault();
        // Call API to mask the email
    };

    return (
        <form onSubmit={handleSubmit}>
            <label htmlFor="email">Enter your email:</label>
            <input type="email" id="email" value={email}
                   onChange={(e) => setEmail(e.target.value)} required/>
            <button type="submit">Mask My Email</button>
        </form>
    );
}

export default EmailForm;

Understanding the useReducer hook

What is useReducer?

useReducer is a built-in React hook that manages complex state logic in functional components. It is similar to useState , but it is more suitable for state management when there are multiple sub-values or when the next state depends on the previous one.

Benefits of useReducer

  • Provides a more organized way to handle complex state updates
  • Makes it easier to manage state transitions
  • Allows for easy testing and separation of concerns

Implementing the useReducer hook

Creating the reducer function

Create a new file called emailReducer.js and add the following code:

export const initialState = {
    email: '',
    maskedEmail: '',
    loading: false,
    error: null,
};

export const actionTypes = {
    SET_EMAIL: 'SET_EMAIL',
    MASK_EMAIL_REQUEST: 'MASK_EMAIL_REQUEST',
    MASK_EMAIL_SUCCESS: 'MASK_EMAIL_SUCCESS',
    MASK_EMAIL_FAILURE: 'MASK_EMAIL_FAILURE',
};

export const emailReducer = (state, action) => {
    switch (action.type) {
        case actionTypes.SET_EMAIL:
            return {...state, email: action.payload};
        case actionTypes.MASK_EMAIL_REQUEST:
            return {...state, loading: true, error: null};
        case actionTypes.MASK_EMAIL_SUCCESS:
            return {...state, loading: false, maskedEmail: action.payload};
        case actionTypes.MASK_EMAIL_FAILURE:
            return {...state, loading: false, error: action.payload};
        default:
            return state;
    }
};

Dispatching actions

Modify the EmailForm component to use the useReducer hook and dispatch actions:

import React, {useReducer} from 'react';
import {emailReducer, initialState, actionTypes} from './emailReducer';

function EmailForm() {
    const [state, dispatch] = useReducer(emailReducer, initialState);

    const handleSubmit = async (event) => {
        event.preventDefault();
        dispatch({type: actionTypes.MASK_EMAIL_REQUEST});

        try {
            // Call API to mask the email
            // Assume the API returns a response with the masked email
            const response = await fetch('/api/mask', {
                method: 'POST',
                body: JSON.stringify({email: state.email}),
            });

            const data = await response.json();
            dispatch({
                type: actionTypes.MASK_EMAIL_SUCCESS,
                payload: data.maskedEmail
            });
        } catch (error) {
            dispatch({
                type: actionTypes.MASK_EMAIL_FAILURE,
                payload: error.message
            });
        }
    };

    return (
        <form onSubmit={handleSubmit}>
            <label htmlFor="email">Enter your email:</label>
            <input
                type="email"
                id="email"
                value={state.email}
                onChange={(e) => dispatch({
                    type: actionTypes.SET_EMAIL,
                    payload: e.target.value
                })}
                required
            />
            <button type="submit">Mask My Email</button>
        </form>
    );
}

export default EmailForm;

Setting up the backend

Backend technologies

For the backend, we will use Node.js and Express.js. Create a new folder called backend and initialize a new Node.js project:

mkdir backend
cd backend
npm init -y

Install the required packages:

npm install express cors body-parser

Creating API routes

Create a new file called app.js and set up the basic Express.js server:

const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');

const app = express();
app.use(cors());
app.use(bodyParser.json());

app.post('/api/mask', (req, res) => {
    // Mask email logic will be here
});

app.listen(3001, () => console.log('Server running onport 3001'));

Masking the email

Understanding the masking process

Email masking involves replacing a portion of the email address with a specific character (e.g., asterisks) to hide the actual email address. This protects the user's privacy and prevents spam.

Implementing email masking

Add the following email masking function to your app.js file:

function maskEmail(email) {
    const [localPart, domain] = email.split('@');
    const maskedLocalPart = localPart.slice(0, 3) + '*'.repeat(localPart.length - 3);
    return maskedLocalPart + '@' + domain;
}

Update the /api/mask route to use the maskEmail function:

app.post('/api/mask', (req, res) => {
    const email = req.body.email;
    const maskedEmail = maskEmail(email);
    res.json({maskedEmail});
});

Connecting the frontend and backend

Fetch API

Update the EmailForm component's handleSubmit function to send a request to the backend:

const response = await fetch('http://localhost:3001/api/mask', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({email: state.email}),
});

Handling API responses

Display the masked email and any errors in the EmailForm component:

return (
    <form onSubmit={handleSubmit}>
        <label htmlFor="email">Enter your email:</label>
        <input
            type="email"
            id="email"
            value={state.email}
            onChange={(e) => dispatch({
                type: actionTypes.SET_EMAIL,
                payload: e.target.value
            })}
            required
        />
        <button type="submit">Mask My Email</button>
        {state.maskedEmail &amp;&amp; <p>Masked Email: {state.maskedEmail}</p>}
        {state.error &amp;&amp; <p>Error: {state.error}</p>}
    </form>
);

Implementing best practices

Code organization

Organize your code into folders and files that separate concerns:

  • Components: src/components

  • Reducers: src/reducers

  • API calls: src/api

Error handling

Handle errors gracefully by displaying user-friendly error messages and logging errors for debugging purposes.

Testing the application

Unit tests

Write unit tests for your components, reducers, and utility functions using Jest and React Testing Library.

Integration tests

Perform end-to-end testing using tools like Cypress to ensure that the entire application works as expected.

Deploying the application

Deployment options

Choose a suitable deployment platform for your frontend (e.g., Netlify, Vercel) and backend (e.g., Heroku, AWS Lambda).

Continuous integration

Set up a CI/CD pipeline to automate the deployment process and ensure that your application is always up-to-date.

Conclusion

In this article, we've built a masking email system using React.js and best practices. We've discussed the useReducer hook, demonstrated how to connect the frontend and backend, and provided code examples to guide you through the process. This beginner-friendly guide should have given you a solid understanding of how to create a masking email application using React.js.

FAQs

  • What is email masking? Email masking is a technique to hide a portion of an email address to protect the user's privacy and prevent spam.

  • Why should I use React.js for this project? React.js is a popular JavaScript library that simplifies building user interfaces, making it an ideal choice for creating scalable applications.

  • What is the useReducer hook? The useReducer hook is a built-in React hook for managing complex state logic in functional components. It is particularly useful when managing multiple sub-values or when the next state depends on the previous one.

  • How does the masking email function work? The masking email function splits the email into the local part and domain, then replaces a portion of the local part with a specific character (e.g., asterisks) to hide the actual email address.

  • What should I consider when deploying the application? Choose a suitable deployment platform for your frontend (e.g., Netlify, Vercel) and backend (e.g., Heroku, AWS Lambda), and set up a CI/CD pipeline to automate the deployment process and ensure that your application is always up-to-date.