Single Page Applications (SPAs) have emerged as a modern trend, consolidating all your application functions into a single, cohesive page. In the ever-evolving landscape of SPA development, mastering the right tools and frameworks is essential.
Traditional approaches to frontend development are giving way to more efficient, dynamic, and user-friendly Single Page Application (SPA) frameworks. In this short tutorial, we'll explore three of the most prominent SPA frameworks: Angular, React, and Vue, and learn how to create some basic functionality with them.
An application developed using the traditional frontend development approach is typically built using a combination of HTML, CSS, and JavaScript, and it requires a full page load for each interaction. For example, if you click a "Submit" button, the entire application will reload to handle the user interaction. This results in a less fluid and responsive user experience. Furthermore, maintaining an application that follows traditional frontend development can be more challenging as the application grows.
What's the solution? Fortunately, there are several SPA frameworks available, including Angular, React, and Vue, that make the development process easier and load only the elements that the user is currently executing. These frameworks have gained popularity due to their exceptional efficiency, flexibility, and an array of advanced features such as state management, routing mechanisms, and reusable components.
Besides, when a server loads a traditional site, it is required to load a number of files, including HTML, CSS, JavaScript, and more, which can make the initial loading slow. Even if there are some files that are not required for the initial loading, the server still spends time loading those files. However, when using SPA frameworks, the server only loads files when it is required. This makes the application run faster than the traditional approach.
Let's take a quick overview of the most popular SPA frameworks: Angular, React, and Vue. We will also examine the limitations of these SPA frameworks to assist you in making comparisons among them.
Angular, a robust SPA framework, has emerged as a powerhouse for building large and complex web applications. It offers a comprehensive set of tools, such as routing, form handling, and dependency injection, that streamline development.
Key features | Drawbacks |
---|---|
Angular contains a comprehensive set of tools and functionalities like routing, form handling, dependency injection, and many more. | Requires a significant amount of code. |
It offers two-way data binding, making your application dynamic and loading the changes immediately. | Performance overhead may occur due to large bundle size. |
It enables you to create reusable and maintainable components. | Limited flexibility and customization in some cases. |
Angular provides better tooling support | Require extra support for SEO optimization. |
React, a go-to choice for creating modern web applications, focuses on crafting responsive and dynamic user interfaces. Its component-based architecture promotes code reusability and maintainability.
Key features | Drawbacks |
---|---|
React contains Component-based architecture, enabling you to create reusable components for your application. | Limited to the view layer. It's the part of an application with which users can interact, such as buttons, links, images, etc. |
It uses JSX (JavaScript XML) which allows you to write HTML-like code directly in JavaScript. | Performance may vary based on application size. |
React enables you to convert your SPA in a mobile application easily and quickly through it React-Native syntax. | React evolves rapidly, compatibility issues may occur for new React versions. |
React supports unidirectional data flow and ensures your data flows in a single direction (Parent to child). | --- |
React offers several performance optimization techniques, such as memoization, lazy loading | --- |
Vue has gained popularity for its powerful and user-friendly features, making it ideal for creating highly interactive web applications. Its lightweight nature and flexibility are notable advantages.
Key features | Drawbacks |
---|---|
Vue also supports Component-based architecture | Limited plugins available |
It offers a concise and easy-to-use syntax for handling action events like mouse clicks, drag and drop, scrolling effects, etc. | Complex integration |
Vue contains a watcher that enables you to track data changes in your application. | Vue isn't compatible with older version browsers. (Less than Internet Explorer 11). |
Vue provides excellent performance through its lightweight feature. | --- |
High flexiblity. | --- |
Here is how you can initiate your project with different SPA frameworks. Please note that the SPA frameworks mentioned in this tutorial require Node.js and npm available in your system. So make sure you have Node.js and npm installed on your machine. Let's imagine you're creating a Weather Forecast application.
If you selected Angular, first you need to install Angular CLI with the command:
npm install -g @angular/cli
After successful installation, you can now create your angular application using the command:
ng new my-weather-app
To start your project, move to your project directory and execute the command:
ng serve
You'll have the below file and folder structure after a successful project setup.
- src/ - app/ - app.component.ts - assets/ - environments/ - styles.css - index.html - node_modules/ - angular.json - tsconfig.json - package.json - tslint.json (if used)
Here is a simple "Hello World" example in Angular:
// Angular Hello World Component import { Component } from '@angular/core'; @Component({ selector: 'app-hello-world', template: '<div>Hello, World!</div>', }) export class HelloWorldComponent {}
If you're using React, just type the below command to create your project:
npx create-react-app my-weather-app
To start your project, move to your project directory and execute the command:
npm start
You'll have the below file and folder structure after a successful project setup.
- node_modules/ - public/ - src/ - index.js - App.js - components/ - assets/ - package.json - babel.config.js (if used) - webpack.config.js (if ejected from Create React App)
Here is a simple "Hello World" example in React:
// React Hello World Component import React from 'react'; function HelloWorld() { return <div>Hello, World!</div>; } export default HelloWorld;
In the case of Vue, you need to install the Vue CLI using the command:
npm install -g @vue/cli
Now create your project using:
vue create my-weather-app
To start your project, move to your project directory and execute the command:
npm run serve
You'll have the below file and folder structure after a successful project setup.
- node_modules/ - public/ - src/ - main.js - App.vue - components/ - assets/ - router/ (if using Vue Router) - store/ (if using Vuex) - views/ - package.json - vue.config.js (if needed)
Here is a simple "Hello World" example in Vue:
<!-- Vue.js Hello World Component --> <template> <div>Hello, World! (Vue.js)</div> </template>
Forms play a critical role in any application by letting users provide information and sending it to the system. In this section, we'll build forms using different Single Page Application (SPA) frameworks.
If you plan to use React for your SPA, you can take a look at this simple form developed with React,
import React, { useState } from 'react'; function GetWhether() { const [inputValue, setInputValue] = useState(''); const handleSubmit = (e) => { e.preventDefault(); // Handle form submission here console.log(inputValue); }; return ( <form onSubmit={handleSubmit}> <input type="text" value={inputValue} onChange={(e) => setInputValue(e.target.value)} placeholder="Enter your location" /> <button type="submit">Submit</button> </form> ); } export default MyForm;
Let's explain the code part by part,
Lines | Explanation |
---|---|
const [inputValue, setInputValue] = useState(''); | Handles user input |
const handleSubmit = (e) => { e.preventDefault(); // Handle form submission here console.log(inputValue); }; | This is an action event on user input. Here e.preventDefault(); prevents all system default |
return ( <form onSubmit={handleSubmit}> <input type="text" value={inputValue} onChange={(e) => setInputValue(e.target.value)} placeholder="Enter your location" /> <button type="submit">Submit</button> </form> ); | A form containing one input field and a submit button. |
With Angular, you can design a form like the one below,
<!-- myform.component.html --> <form (ngSubmit)="onSubmit()"> <input type="text" [(ngModel)]="inputValue" placeholder="Enter your location" name="inputField" /> <button type="submit">Submit</button> </form>
// myform.component.ts import { Component } from '@angular/core'; @Component({ selector: 'app-myform', templateUrl: './myform.component.html', styleUrls: ['./myform.component.css'] }) export class SimpleFormComponent { inputValue: string = ''; onSubmit() { // Handle form submission here console.log(this.inputValue); } }
Let's break the code and see how it works,
Lines | Explanation |
---|---|
@Component({ selector: 'app-myform', templateUrl: './myform.component.html', styleUrls: ['./myform.component.css'] }) | Initializing the resources |
export class SimpleFormComponent { inputValue: string = ''; onSubmit() { // Handle form submission here console.log(this.inputValue); } } | Handles the user input. Here the inputValue stores the user input and the method onSubmit() processes the user input |
Here is a simple form designed in Vue.
<template> <form @submit.prevent="onSubmit"> <input v-model="inputValue" type="text" placeholder="Enter your location" /> <button type="submit">Submit</button> </form> </template>
<script> export default { data() { return { inputValue: '' }; }, methods: { onSubmit() { // Handle form submission here console.log(this.inputValue); } } }; </script>
Check the explanation table to understand how the code works.
Lines | Explanation |
---|---|
data() { return { inputValue: '' }; }, | Handles user input |
methods: { onSubmit() { // Handle form submission here console.log(this.inputValue); } } | the method onSubmit() processes the user input |
API calls involve sending requests to a remote server to fetch specific data, and the server responds with the requested information. Let's explore how to make API calls in single-page application (SPA) frameworks.
Here is a simple API call with React.
import React, { useEffect, useState } from 'react'; function App() { const [data, setData] = useState(null); useEffect(() => { fetch('https://api.example.com/data') // Replace with your API endpoint .then((response) => response.json()) .then((data) => setData(data)) .catch((error) => console.error('API Call Failed: ', error)); }, []); return ( <div> {data ? ( <div>{JSON.stringify(data)}</div> ) : ( <div>Loading...</div> )} </div> ); } export default App;
Let's take a quick look at the explanation table that makes it easy to understand
Lines | Explanation |
---|---|
const [data, setData] = useState(null); | Handles user data |
useEffect(() => { fetch('https://api.example.com/data') // Replace with your API endpoint .then((response) => response.json()) .then((data) => setData(data)) .catch((error) => console.error('API Call Failed: ', error)); }, []); | Makes the API call using the fetch() , get the response data and process the user data |
return ( <div> {data ? ( <div>{JSON.stringify(data)}</div> ) : ( <div>Loading...</div> )} </div> ); | Shows the result of API call |
If you're using Angular, you can make the API call like the one below,
import { Component, OnInit } from '@angular/core'; import { HttpClient } from '@angular/common/http'; @Component({ selector: 'app-root', templateUrl: './app.component.html', }) export class AppComponent implements OnInit { data: any; constructor(private http: HttpClient) {} ngOnInit() { this.http.get('https://api.example.com/data') // Replace with your API endpoint .subscribe((response) => { this.data = response; }, (error) => { console.error('API call failed: ', error); }); } }
Let's check the explanation table for more details,
Function | Explanation |
---|---|
@Component({ selector: 'app-root', templateUrl: './app.component.html', }) | Initializing Resources |
data: any; | Variable that holds user data |
ngOnInit() { this.http.get('https://api.example.com/data') // Replace with your API endpoint .subscribe((response) => { this.data = response; }, (error) => { console.error('API call failed: ', error); }); } | Makes the HTTP requst using this.http.get() and process the response data. |
Using Vue, making an API call is much simpler,
<template> <div> {{ data ? JSON.stringify(data) : 'Loading...' }} </div> </template>
<script> import axios from 'axios'; export default { data() { return { data: null, }; }, mounted() { axios.get('https://api.example.com/data') // Replace with your API endpoint .then((response) => { this.data = response.data; }) .catch((error) => { console.error('API call failed: ', error); }); }, }; </script>
Let's take a quick look at the explanation table that makes it easy to understand
Function | Explanation |
---|---|
data() { return { data: null, }; }, | Handles the data |
mounted() { axios.get('https://api.example.com/data') // Replace with your API endpoint .then((response) => { this.data = response.data; }) .catch((error) => { console.error('API call failed: ', error); }); }, | Makes the HTTP requset using axios.get() and process the response data. |
Showing data is a common task in any Single Page Application (SPA). In this section, we'll explore how to display data using React, Angular, and Vue.
Here is how you can display our results in React.
import React from 'react'; function App() { const data = ["Item 1", "Item 2", "Item 3"]; return ( <div> <h1>Items:</h1> <ul> {data.map((item, index) => ( <li key={index}>{item}</li> ))} </ul> </div> ); } export default App;
Let's take a quick look at the explanation table,
Function | Explanation |
---|---|
const data = ["Item 1", "Item 2", "Item 3"]; | Your data |
{data.map((item, index) => ( <li key={index}>{item}</li> ))} | Mapping the data and making it visible using <li></li> |
Here is a simple data visualization in Angular
<!-- app.component.html --> <div> <h1>Items:</h1> <ul> <li *ngFor="let item of data">{{ item }}</li> </ul> </div>
// app.component.ts import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', }) export class AppComponent { data = ["Item 1", "Item 2", "Item 3"]; }
This is how the code works,
Function | Explanation |
---|---|
<li *ngFor="let item of data">{{ item }}</li> | Visualizing the data in <li></li> tag |
@Component({ selector: 'app-root', templateUrl: './app.component.html', }) | Initializing the components |
data = ["Item 1", "Item 2", "Item 3"]; | Data to visualize |
This is how you can visualize data in Vue,
<template> <div> <h1>Items:</h1> <ul> <li v-for="(item, index) in data" :key="index">{{ item }}</li> </ul> </div> </template>
<script> export default { data() { return { data: ["Item 1", "Item 2", "Item 3"], }; }, }; </script>
Let's take a close view of the code,
Function | Explanation |
---|---|
<li v-for="(item, index) in data" :key="index">{{ item }}</li> | Visualizing the data in <li></li> tag |
data() { return { data: ["Item 1", "Item 2", "Item 3"], }; }, }; | Handles the data |
A 'state' is data that an application keeps to manage its behavior and user interaction. For instance, when you enter something in an input field, you alter the state of that field from empty to having a value.
Let's delve into how SPA frameworks handle these state changes:
Here is how React manages states,
import React, { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); const increment = () => { setCount(count + 1); }; return ( <div> <p>Count: {count}</p> <button onClick={increment}>Increment</button> </div> ); } export default Counter;
Let's see how the code works,
Function | Explanation |
---|---|
const [count, setCount] = useState(0); | Handles the user state |
const increment = () => { setCount(count + 1); }; | Here the method increment() take action during any state change |
return ( <div> <p>Count: {count}</p> <button onClick={increment}>Increment</button> </div> ); | Showing the output after state change |
Here is an example of state management in Angular.
<!-- counter.component.html --> <div> <p>Count: {{ count }}</p> <button (click)="increment()">Increment</button> </div>
// counter.component.ts import { Component } from '@angular/core'; @Component({ selector: 'app-counter', templateUrl: './counter.component.html', }) export class CounterComponent { count: number = 0; increment() { this.count++; } }
Let's take a quick look at the explanation table that makes it easy to understand,
Function | Explanation |
---|---|
<div> <p>Count: {{ count }}</p> <button (click)="increment()">Increment</button> </div> | Shows the output after state change |
@Component({ selector: 'app-counter', templateUrl: './counter.component.html', }) | Initializing resources |
export class CounterComponent { count: number = 0; increment() { this.count++; } } | Main class contain a method ncrement() handles the state change. In this case, it increments the value when a user clicks the Increment button |
If you're using Vue, you can manage the states like the below,
<template> <div> <p>Count: {{ count }}</p> <button @click="increment">Increment</button> </div> </template>
<script> export default { data() { return { count: 0, }; }, methods: { increment() { this.count++; }, }, }; </script>
Let's zoom in the code,
Function | Explanation |
---|---|
<template> <div> <p>Count: {{ count }}</p> <button @click="increment">Increment</button> </div> </template> | A HTML template containing necessary components |
data() { return { count: 0, }; }, | Handles the state data |
methods: { increment() { this.count++; }, }, }; | the method increment() handles the state change. In this case, it increments the value when a user clicks the Increment button |
Now that you can design a form for your application, control the state, make API calls to get the necessary data, and display it to your users, there's one aspect we haven't addressed: the visual appeal.
Let's optimize the UI to make it more attractive.
By utilizing CSS, or Cascading Style Sheets, you can easily enhance the friendliness and visual appeal of your application's user interface. It is a stylesheet language that enables you to define the visual presentation of your web application. There are three ways to apply CSS in your application:
Inline CSS In this way, you need not use any separate CSS file for styling. You can define the CSS inside the HTML element using the "style" attribute.
<p style="color:red">Your text here</p>
Internal CSS
This method allows you to style your HTML elements inside your HTML file using the <style>
tag.
<style> p { color: red; } </style> <p>Your text here</p>
External CSS You need to create a separate CSS file to define all your styles for your application. The advantage of using this method is that you can share the CSS file across all your application files. So you need not to define the same styling again and again.
External CSS libraries consist of pre-defined CSS styles that you can readily apply to your application without the need to create styles from scratch. For instance, Bootstrap is a well-known CSS library that enables you to achieve perfect alignment, responsiveness, and an attractive appearance for your application with a simple inclusion using a <link>
tag.
Here are a few steps that you can take to include external CSS libraries in your application
Step 1: Find an External CSS library First, you need to choose a CSS library that suits your project's needs. Popular CSS libraries include Bootstrap, Foundation, Bulma, Materialize, and many others. These libraries provide pre-designed styles and layout components that you can easily incorporate into your project.
Step 2: Import the library using CDN CDN allows you to import a library using a link without downloading the library. As for Bootstrap, you can include it in your project like the below,
<!-- Link to Bootstrap CSS via a CDN --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
Now you can apply the styles directly to your application like the below,
<button class="btn btn-primary">Click me</button>
You'll get all the predefined styles in the documentation or official website of the library you selected.
In the end, let's take a quick look at some tips and best practices that make your application UI look great and well organized in any screen size,
Make it Mobile First To make your application perfectly aligned in any screen size, start designing for mobile devices first and then progressively enhance the design for larger screens. This approach ensures a solid foundation for smaller screens and helps prioritize content and performance.
Don't make the Layout fixed When defining properties like the width and height of any elements, use relative units like percentages instead of using fixed width. This will allow the element to adapt to different screen sizes.
Use Media Queries CSS contains media queries that allow you to set styles for different screen sizes. Carefully define the breakpoints where your UI needs adjustments such as changing the number of columns, and font sizes or hiding/showing certain elements.
@media (max-width: 768px) { /* Styles for screens up to 768px wide */ } @media (min-width: 769px) { /* Styles for screens 769px wide and larger */ }
Use Relative Font Sizing When sizing font, Use relative units like em or rem. This will allow you to scale the texts appropriately on different devices, making the text more readable on both small and large screens.
Create Mobile-Friendly Navigation For creating a navigation menu, always make it mobile-friendly to save space on small devices. Also, make sure navigation items are easily accessible and usable on touch screens.