Design Pattern in A Nutshell | Routing in React with React Router DOM v6 using Composite Pattern
Design Pattern in A Nutshell
Design pattern is a common solution for frequently occurring software design problems. Design patterns are used to overcome common design problems by providing proven solutions in the form of patterns that can be applied to different situations.
Design patterns assist us in writing code that is easier to maintain, comprehend, and improve. We may get more manageable, extendable, and reusable code by employing design patterns.
Model-View-Controller (MVC), Factory, Singleton, Observer, Composite and Strategy are some prevalent design patterns. Depending on the problem being solved, each design pattern has unique qualities and use.
Examples of Design Pattern
Some examples of common design patterns:
- Singleton Design Pattern
The Singleton design pattern ensures that only one instance of a class exists in the system at any given time, and provides a global point of access to it.
class Singleton {
constructor() {
if (!Singleton.instance) {
Singleton.instance = this;
}
return Singleton.instance;
}
}
const instance1 = new Singleton();
const instance2 = new Singleton();
console.log(instance1 === instance2); // true
2. Factory Design Pattern
The Factory design pattern is used to create objects without specifying the exact class of object that will be created.
class Product {
constructor(name) {
this.name = name;
}
}
class ProductFactory {
createProduct(name) {
return new Product(name);
}
}
const productFactory = new ProductFactory();
const product1 = productFactory.createProduct('Product 1');
const product2 = productFactory.createProduct('Product 2');
console.log(product1.name); // Product 1
console.log(product2.name); // Product 2
3. Observer Design Pattern
The Observer design pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
class Subject {
constructor() {
this.observers = [];
}
addObserver(observer) {
this.observers.push(observer);
}
notify(data) {
for (const observer of this.observers) {
observer.update(data);
}
}
}
class Observer {
update(data) {
console.log(`Received data: ${data}`);
}
}
const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notify('Hello observers!');
// Output:
// Received data: Hello observers!
// Received data: Hello observers!
4. Composite Design Pattern
The Composite design pattern is used to create hierarchical structures of objects (like a tree) that can be treated as a single object.
class Component {
constructor(name) {
this.name = name;
}
add(component) {}
}
class Leaf extends Component {
constructor(name) {
super(name);
}
}
class Composite extends Component {
constructor(name) {
super(name);
this.children = [];
}
add(component) {
this.children.push(component);
}
}
const root = new Composite('root');
const leaf1 = new Leaf('leaf 1');
const leaf2 = new Leaf('leaf 2');
const composite = new Composite('composite');
const leaf3 = new Leaf('leaf 3');
root.add(leaf1);
root.add(leaf2);
composite.add(leaf3);
root.add(composite);
// Result:
// root
// --leaf 1
// --leaf 2
// --composite
// ----leaf 3
What is Routing in Web Development ?
Routing is the process of traveling between multiple pages or views inside a single-page application in front-end web development (SPA). Instead of loading new pages every time the user navigates to a new place, SPAs dynamically change the content on the current page.
Routing enables user to navigate between different pages of the SPA without refreshing the entire page.
Typically, a router library is used to achieve this, listening for changes in the URL and updating the page’s content as necessary. Using routing, developers may construct more dynamic and interactive online apps that deliver a better user experience.
Composite Pattern
Routing in React using React Router follows the composite design pattern. In this pattern, a complex component is built from simple components. React Router components like BrowserRouter, Routes, and Route are all designed to be easily composed to create a complex routing system for your application. This makes it easy to create a highly modular and maintainable application, as the routing functionality can be separated from other application logic. The Composition pattern is widely used in React because it promotes code reuse, modular design, and easy maintainability.
React Router
React Router is a popular framework for providing client-side routing in react applications. It has two different variants:
react-router-dom
: for web applications (using ReactJS)react-router-native
: for mobile development (using React Native)
React Router DOM
In this forum, I will discuss specifically about react-router-dom
. In version 6 of the react-router-dom
package, the following components are used to configure routing:
BrowserRouter: This component is used to wrap the root of the application and offer routing capability to the application. It monitors changes in the URL and modifies the Interface appropriately.
Routes: This component is used to specify the routes for your application. It comprises one or more Route components, each determining a distinct route.
Route: This component is used to specify a specific route in your application. It accepts a path prop, which provides the URL path that should match the route. It also accepts a component prop, which defines the React component that should be rendered when the route is matched.
React Router DOM v6 (Current Latest)
React Router v6 improved the API over the previous version by introducing various modifications. Here are some of the reasons:
Simpler API: React Router v6’s API is more user-friendly and straightforward, making it simpler for developers to use and comprehend.
Better Performance: The new React Router version has been performance enhanced, making it quicker and more effective than the old version.
Improved Type Safety: React Router’s latest version is built with TypeScript, which offers greater type safety and makes it simpler to spot issues early in the development process.
Enhanced Navigation: The new React Router version offers improved navigation functionality, including nested routes and dynamic routes.
Installation
Using npm, you can simply run this code on terminal to install the latest version of react-router-dom
:
npm install react-router-dom
Basic Example
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/user" element={<User />} />
</Routes>
</Router>
);
}
In this example, the BrowserRouter
(which I defined it as Router
for convinience) component wraps the Routes
component, which contains two Route
components. The first Route
component matches the root “/” URL path and renders the Home
component, while the second Route
component matches the “/user” URL path and renders the User
component.
Nested Routes Example
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/user" element={<User />}>
<Route path="/profile" element={<Profile />} />
<Route path="/account" element={<Account />} />
</Route>
</Routes>
</Router>
);
}
In this example, we can see that the parent “/user” Route
has 2 children.
The first Route
component matches the root “/profile” URL path and renders the Profile
component, while the second Route
component matches the “/account” URL path and renders the account
component.
If you happen to use React Router for your React application, Nested Routes can boost your user experience tremendously by giving your users access to very specific parts of your applications while sharing these parts as URLs.