E-Commerce Product Viewer app using class componants
React Class Component Lifecycle Methods :
1) Mounting
2) Updating
3) Unmounting
4) Error Handling (Error Boundary)
File- 1. main.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import ErrorBoundary from './ErrorBoundary';
ReactDOM.render(
<ErrorBoundary>
<App />
</ErrorBoundary>,
document.getElementById('root')
);
2. App.js
import React from 'react';
import ProductList from './ProductList';
class App extends React.Component {
constructor() {
super();
this.state = {
showProducts: true
};
console.log('App Constructor');
}
toggleProductView = () => {
this.setState(prev => ({ showProducts: !prev.showProducts }));
};
render() {
console.log('App Render');
return (
<div style={{ padding: '20px', fontFamily: 'Arial' }}>
<h1> My E-Commerce Site</h1>
<button onClick={this.toggleProductView}>
{this.state.showProducts ? 'Hide' : 'Show'} Products
</button>
{this.state.showProducts && <ProductList />}
</div>
);
}
}
export default App;
3. ProductList.js – Mount/Update/Unmount Logic
import React from 'react';
import ProductCard from './ProductCard';
class ProductList extends React.Component {
constructor() {
super();
this.state = {
products: [],
message: 'Loading...',
};
console.log('ProductList Constructor');
}
static getDerivedStateFromProps(props, state) {
console.log('ProductList getDerivedStateFromProps');
return null;
}
componentDidMount() {
console.log('ProductList componentDidMount');
// Simulate API call
setTimeout(() => {
this.setState({
products: [
{ id: 1, name: 'T-shirt', price: 499 },
{ id: 2, name: 'Shoes', price: 999 },
{ id: 3, name: 'Watch', price: 1999 }
],
message: ''
});
}, 1000);
}
shouldComponentUpdate(nextProps, nextState) {
console.log('ProductList shouldComponentUpdate');
return true;
}
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log('ProductList getSnapshotBeforeUpdate');
return null;
}
componentDidUpdate() {
console.log('ProductList componentDidUpdate');
}
componentWillUnmount() {
console.log('ProductList componentWillUnmount');
}
render() {
console.log('ProductList Render');
return (
<div>
<h2> Available Products</h2>
<p>{this.state.message}</p>
{this.state.products.map(p => (
<ProductCard key={p.id} product={p} />
))}
</div>
);
}
}
export default ProductList;
4. ProductCard.js
import React from 'react';
class ProductCard extends React.PureComponent {
constructor(props) {
super(props);
console.log(`ProductCard Constructor - ${props.product.name}`);
}
componentDidMount() {
console.log(`ProductCard componentDidMount - $
{this.props.product.name}`);
}
componentWillUnmount() {
console.log(`ProductCard componentWillUnmount - $
{this.props.product.name}`);
}
render() {
console.log(`ProductCard Render - ${this.props.product.name}`);
const { name, price } = this.props.product;
return (
<div style={{
border: '1px solid gray',
padding: '10px',
margin: '10px 0',
borderRadius: '8px'
}}>
<h3>{name}</h3>
<p>Price: ₹{price}</p>
</div>
);
}
}
export default ProductCard;
5. ErrorBoundary.js – componentDidCatch
import React from 'react';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
console.log('ErrorBoundary Constructor');
}
static getDerivedStateFromError(error) {
console.log('ErrorBoundary getDerivedStateFromError');
return { hasError: true };
}
componentDidCatch(error, info) {
console.log('ErrorBoundary componentDidCatch');
// Send to logging service
}
render() {
console.log('ErrorBoundary Render');
if (this.state.hasError) {
return <h2>Something went wrong.</h2>;
}
return this.props.children;
}
}
export default ErrorBoundary;
Output:
Check flow of application on console
-------------------------------------------------------------------------------------------
E-Commerce Product Viewer app implemented using React Hooks
Mounting (useEffect)
Updating (via state & useEffect)
Unmounting (useEffect cleanup)
Error Handling (using ErrorBoundary with class component, as React
still requires class for that)
File 1: main.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import ErrorBoundary from './ErrorBoundary';
ReactDOM.render(
<ErrorBoundary>
<App />
</ErrorBoundary>,
document.getElementById('root')
);
File 2: App.js
import React, { useState } from 'react';
import ProductList from './ProductList';
const App = () => {
const [showProducts, setShowProducts] = useState(true);
console.log('App Render');
const toggleProductView = () => {
setShowProducts(prev => !prev);
};
return (
<div style={{ padding: '20px', fontFamily: 'Arial' }}>
<h1> My E-Commerce Site</h1>
<button onClick={toggleProductView}>
{showProducts ? 'Hide' : 'Show'} Products
</button>
{showProducts && <ProductList />}
</div>
);
};
export default App;
File 3: ProductList.jsx
import React, { useEffect, useState } from 'react';
import ProductCard from './ProductCard';
const ProductList = () => {
const [products, setProducts] = useState([]);
const [message, setMessage] = useState('Loading...');
// Mounting
useEffect(() => {
console.log('ProductList Mounted');
const timeout = setTimeout(() => {
setProducts([
{ id: 1, name: 'T-shirt', price: 499 },
{ id: 2, name: 'Shoes', price: 999 },
{ id: 3, name: 'Watch', price: 1999 }
]);
setMessage('');
}, 1000);
// Unmounting
return () => {
console.log('ProductList Unmounted');
clearTimeout(timeout); // cleanup if needed
};
}, []);
// Updating
useEffect(() => {
if (products.length > 0) {
console.log('ProductList Updated');
}
}, [products]);
console.log('ProductList Render');
return (
<div>
<h2> Available Products</h2>
<p>{message}</p>
{products.map(p => (
<ProductCard key={p.id} product={p} />
))}
</div>
);
};
export default ProductList;
File 4: ProductCard.jsx
import React, { useEffect } from 'react';
const ProductCard = ({ product }) => {
const { name, price } = product;
useEffect(() => {
console.log(`ProductCard Mounted - ${name}`);
return () => {
console.log(`ProductCard Unmounted - ${name}`);
};
}, []);
console.log(`ProductCard Render - ${name}`);
return (
<div style={{
border: '1px solid gray',
padding: '10px',
margin: '10px 0',
borderRadius: '8px'
}}>
<h3>{name}</h3>
<p>Price: ₹{price}</p>
</div>
);
};
export default ProductCard;
File 5: ErrorBoundary.js
Hooks cannot implement componentDidCatch, so we keep this part as a
class:
import React from 'react';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
console.log('ErrorBoundary Constructor');
}
static getDerivedStateFromError(error) {
console.log('ErrorBoundary getDerivedStateFromError');
return { hasError: true };
}
componentDidCatch(error, info) {
console.log('ErrorBoundary componentDidCatch');
}
render() {
console.log('ErrorBoundary Render');
if (this.state.hasError) {
return <h2>Something went wrong.</h2>;
}
return this.props.children;
}
}
export default ErrorBoundary;