Developing the Frontend
Building a user-friendly and responsive frontend is key to providing a good user experience. In this guide, we’ll walk through setting up a simple frontend using React, integrating it with your Node.js backend, and handling user authentication and session management.
Setting Up a Simple Front-End Using React
React is a popular JavaScript library for building user interfaces, especially single-page applications (SPAs).
1. Create the React App:
Start by creating a new React app using create-react-app
, which sets up everything you need with a single command.
npx create-react-app client
cd client
2. Organize the Project Structure:
Inside the src
folder, you can create directories for components, pages, and services to keep your code organized.
Example Structure:
/src
/components
TaskList.js
TaskForm.js
/pages
HomePage.js
LoginPage.js
RegisterPage.js
/services
authService.js
taskService.js
App.js
index.js
3. Create Basic Components:
Let’s start by creating a simple TaskList
component to display tasks:
// src/components/TaskList.js
import React from 'react';
const TaskList = ({ tasks }) => {
return (
<ul>
{tasks.map(task => (
<li key={task.id}>
{task.title} - {task.completed ? 'Completed' : 'Pending'}
</li>
))}
</ul>
);
};
export default TaskList;
And a TaskForm
component for adding new tasks:
// src/components/TaskForm.js
import React, { useState } from 'react';
const TaskForm = ({ onAddTask }) => {
const [title, setTitle] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
if (title.trim()) {
onAddTask({ title, completed: false });
setTitle('');
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="New task"
/>
<button type="submit">Add Task</button>
</form>
);
};
export default TaskForm;
4. Set Up Routing:
Install react-router-dom
to handle routing in your app:
npm install react-router-dom
Then, set up basic routing in App.js
:
// src/App.js
import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import HomePage from './pages/HomePage';
import LoginPage from './pages/LoginPage';
import RegisterPage from './pages/RegisterPage';
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/register" element={<RegisterPage />} />
</Routes>
</Router>
);
}
export default App;
Integrating the Front-End with the Node.js Backend
Now that you have a basic frontend set up, the next step is to connect it to your Node.js backend.
1. Create Service Functions for API Calls:
Inside the services
directory, create functions to handle API requests. For example, here’s how you might set up a service to fetch tasks from your backend:
// src/services/taskService.js
import axios from 'axios';
const API_URL = 'http://localhost:5000/api/tasks';
export const getTasks = async () => {
const response = await axios.get(API_URL);
return response.data;
};
export const addTask = async (task) => {
const response = await axios.post(API_URL, task);
return response.data;
};
2. Use the Service Functions in Your Components:
In HomePage.js
, you can use these service functions to fetch and display tasks:
// src/pages/HomePage.js
import React, { useEffect, useState } from 'react';
import { getTasks, addTask } from '../services/taskService';
import TaskList from '../components/TaskList';
import TaskForm from '../components/TaskForm';
const HomePage = () => {
const [tasks, setTasks] = useState([]);
useEffect(() => {
const fetchTasks = async () => {
const tasks = await getTasks();
setTasks(tasks);
};
fetchTasks();
}, []);
const handleAddTask = async (newTask) => {
const savedTask = await addTask(newTask);
setTasks([...tasks, savedTask]);
};
return (
<div>
<h1>Task Manager</h1>
<TaskForm onAddTask={handleAddTask} />
<TaskList tasks={tasks} />
</div>
);
};
export default HomePage;
Handling User Authentication and Session Management
Authentication is a critical part of any web application that deals with user data. Let’s add basic user authentication to your frontend.
1. Create Authentication Service:
Create an authService.js
file in the services
directory to handle login and registration:
// src/services/authService.js
import axios from 'axios';
const API_URL = 'http://localhost:5000/api/users';
export const register = async (userData) => {
const response = await axios.post(`${API_URL}/register`, userData);
return response.data;
};
export const login = async (userData) => {
const response = await axios.post(`${API_URL}/login`, userData);
if (response.data.token) {
localStorage.setItem('user', JSON.stringify(response.data));
}
return response.data;
};
export const logout = () => {
localStorage.removeItem('user');
};
export const getCurrentUser = () => {
return JSON.parse(localStorage.getItem('user'));
};
2. Create Authentication Pages:
Set up basic login and registration pages using these service functions.
LoginPage.js:
// src/pages/LoginPage.js
import React, { useState } from 'react';
import { login } from '../services/authService';
import { useNavigate } from 'react-router-dom';
const LoginPage = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const navigate = useNavigate();
const handleSubmit = async (e) => {
e.preventDefault();
try {
await login({ email, password });
navigate('/');
} catch (error) {
console.error('Login failed:', error);
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
required
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
required
/>
<button type="submit">Login</button>
</form>
);
};
export default LoginPage;
RegisterPage.js:
// src/pages/RegisterPage.js
import React, { useState } from 'react';
import { register } from '../services/authService';
import { useNavigate } from 'react-router-dom';
const RegisterPage = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const navigate = useNavigate();
const handleSubmit = async (e) => {
e.preventDefault();
try {
await register({ email, password });
navigate('/login');
} catch (error) {
console.error('Registration failed:', error);
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
required
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
required
/>
<button type="submit">Register</button>
</form>
);
};
export default RegisterPage;
3. Protecting Routes:
To protect routes that require authentication, you can create a simple PrivateRoute
component:
// src/components/PrivateRoute.js
import React from 'react';
import { Navigate } from 'react-router-dom';
import { getCurrentUser } from '../services/authService';
const PrivateRoute = ({ children }) => {
const user = getCurrentUser();
return user ? children : <Navigate to="/login" />;
};
export default PrivateRoute;
Then use it in your routing setup:
// src/App.js
import PrivateRoute from './components/PrivateRoute';
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<PrivateRoute><HomePage /></PrivateRoute>} />
<Route path="/login" element={<LoginPage />} />
<Route path="/register" element={<RegisterPage />} />
</Routes>
</Router>
);
}
Conclusion
Developing the frontend involves setting up a user interface, connecting it to the backend, and managing user authentication and sessions. By following these steps, you can create a responsive, functional frontend that interacts seamlessly with your Node.js backend, providing a smooth user experience.
Related Chapters
- What is Node.js?
- Setting Up the Development Environment
- Understanding the Basics
- Node.js Modules
- Working with the File System
- Node.js Package Manager (npm)
- Asynchronous Programming in Node.js
- Building a Web Server with Node.js
- Introduction to Express.js
- Working with Databases
- Authentication and Security
- RESTful APIs with Node.js
- Testing in Node.js
- Planning the Project
- Developing the Backend with Node.js
- Developing the Frontend
- Deployment