Skip to content

✅ Completed understanding of React lifecycle in both Function and Cla… #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 99 additions & 17 deletions client/src/component/ClassComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,108 @@
import { Component } from "react";
import { UserFetchApi } from "../type/crud";
import React, { Component } from "react";
import Table from "../ui/Table";
import { User } from "../type/crud";
interface Props{
result:UserFetchApi
import { User, UserFetchApi } from "../type/crud";

interface Props {
result: UserFetchApi;
}

interface Column<T> {
headerName: string;
accessor: keyof T;
}

class ClassComponent extends Component<Props>{
render() {
interface Column<T> {
headerName: string;
accessor: keyof T;
}

const columnData: Column<User>[] = [
type State = {
users: User[];
status: "idle" | "loading" | "success" | "error";
count: number;
};

class ClassComponent extends Component<Props, State> {
constructor(props: Props) {
// 🔧 Mounting Phase: constructor
// Called once when the component is created.
// Best place to initialize `state` and bind methods.
super(props);
console.log("🔧 constructor: called once before component mounts");

this.state = {
users: [],
status: "idle",
count: 0,
};
}

static getDerivedStateFromProps(nextProps: Props, prevState: State) {
// 📥 Called on every render (both mount and update)
// Use to derive state from props.
// Rarely needed. Avoid setting state here unless necessary.
console.log("📥 getDerivedStateFromProps");
return null;
}

componentDidMount(): void {
// ✅ Mounting Phase: componentDidMount
// Called once, right after the component is added to the DOM.
// Ideal for API calls, subscriptions, etc.
console.log("✅ componentDidMount: component is now in the DOM");
}

shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
// 🔍 Updating Phase: shouldComponentUpdate
// Use this to prevent unnecessary renders.
// Return false to skip re-render.
console.log("🔍 shouldComponentUpdate");
return true; // default is true
}

getSnapshotBeforeUpdate(prevProps: Props, prevState: State) {
// 📸 Called right before DOM updates
// Used to capture scroll positions, etc., before DOM changes
console.log("📸 getSnapshotBeforeUpdate");
return null;
}

componentDidUpdate(prevProps: Props, prevState: State, snapshot: any) {
// 🔁 Updating Phase: componentDidUpdate
// Called after every re-render caused by state or props change
console.log("🔁 componentDidUpdate");
}

componentWillUnmount(): void {
// 🧹 Unmounting Phase: componentWillUnmount
// Called once, just before the component is removed from the DOM
// Ideal for cleanup: timers, subscriptions, event listeners
console.log(
"🧹 componentWillUnmount: cleanup before component is removed from DOM"
);

// ⚠️ NOTE:
// In dev, React Fast Refresh (HMR) may unmount/remount your component automatically,
// causing this to run on every save/hot update. This is expected during development.
}

render() {
// 🎨 Called during Mounting and Updating
// Should return JSX — it must be a pure function (no side effects).
console.log(
`[DEBUG] 🎨 render() at ${new Date().toLocaleTimeString()}`
);

const columnData: Column<User>[] = [
{ headerName: "Name", accessor: "name" },
{ headerName: "Email", accessor: "email" },
{ headerName: "City", accessor: "city" },
];
const {data,getDataofUser,status} = this.props.result;
return <Table<User> columns={columnData} data={data.data}/>
}

const { data } = this.props.result;

return (
<div>
<h2>React Lifecycle Demo (Class Component)</h2>
<Table<User> columns={columnData} data={data.data} />
</div>
);
}
}
export default ClassComponent

export default ClassComponent;
223 changes: 127 additions & 96 deletions client/src/component/FunctionComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,120 +1,151 @@
// import logo from './logo.svg';
import { ChangeEvent,useState } from 'react';
import { useHookGetData,useHookDeleteData, useHookPostData, useHookUpdateData } from '../api/crud';
import { User, UserFetchApi } from '../type/crud';
import { ChangeEvent, useEffect, useState } from "react";
import {
useHookGetData,
useHookDeleteData,
useHookPostData,
useHookUpdateData,
} from "../services/crud";
import { User, UserFetchApi } from "../type/crud";

function FunctionComponent() {
const result:UserFetchApi = useHookGetData()
const {status,data,getDataofUser} =result

const {deleteDataofUser} = useHookDeleteData()
const {createDataofUser} = useHookPostData()
const {updateDataofUser} = useHookUpdateData()

const userObj = {
name:"",
email:"",
city:"",
}
// 🧠 useState is the Function Component equivalent of this.state in class components
const userObj = { name: "", email: "", city: "" };
const [form, setForm] = useState({ ...userObj });
const [isEditId, setEditId] = useState("");

const [form,setForm] = useState({...userObj})
const [isEditId,setEditId] = useState('')
// 🧠 Custom hooks managing API data (similar to componentDidMount + data logic)
const result: UserFetchApi = useHookGetData();
const { status, data, getDataofUser } = result;

const { deleteDataofUser } = useHookDeleteData();
const { createDataofUser } = useHookPostData();
const { updateDataofUser } = useHookUpdateData();

const handaledeleteuserData = async (id:string)=>{
try{
await deleteDataofUser(id)
getDataofUser()
}catch (error){
console.log(error)
}
}
// 🔄 useEffect = lifecycle in functional components
// ✅ Runs once when component is mounted (like componentDidMount)
useEffect(() => {
console.log("✅ useEffect → acts like componentDidMount");
getDataofUser();

const handaleUpdateUserData = async ()=>{
try{
console.log('isEditId',isEditId)
await updateDataofUser(isEditId,form)
setForm({...userObj})
setEditId('')
}catch (error){
console.log(error)
}
}
return () => {
// 🧹 Cleanup function = componentWillUnmount
console.log("🧹 Cleanup → acts like componentWillUnmount");
};
}, []); // [] = only once (mount + unmount)

const handalesaveUsreData = async (e:ChangeEvent<HTMLFormElement>)=>{
e.preventDefault()
try{
if(isEditId){
await handaleUpdateUserData()
}else{
await createDataofUser(form)
const handleDeleteUserData = async (id: string) => {
try {
await deleteDataofUser(id);
getDataofUser();
} catch (error) {
console.log(error);
}
await getDataofUser()
};

}catch(error){
console.log(error)
}
}
const handleUpdateUserData = async () => {
try {
console.log("Editing ID →", isEditId);
await updateDataofUser(isEditId, form);
setForm({ ...userObj });
setEditId("");
} catch (error) {
console.log(error);
}
};

const handleSaveUserData = async (e: ChangeEvent<HTMLFormElement>) => {
e.preventDefault();
try {
if (isEditId) {
await handleUpdateUserData();
} else {
await createDataofUser(form);
}
getDataofUser();
} catch (error) {
console.log(error);
}
};

const handleUpdate = (obj: User) => {
setEditId(obj._id);
setForm({ name: obj.name, email: obj.email, city: obj.city });
};

const handaleUpdate = (obj:User)=>{
setEditId(obj._id)
setForm({name:obj.name,email:obj.email,city:obj.city})
}
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
setForm((prev) => ({ ...prev, [e.target.name]: e.target.value }));
};

const handaleChnage = (e:ChangeEvent<HTMLInputElement>)=>{
setForm(prev=>({...prev,[e.target.name]:e.target.value}))
}
return (
<div className="container">
<form className='input-box' onSubmit={handalesaveUsreData}>
<input type='text' name="name" value={form.name} onChange={handaleChnage}/>
<input type='email'name="email" value={form.email} onChange={handaleChnage}/>
<input type='text' name="city" value={form.city} onChange={handaleChnage}/>
{isEditId?
<>
<button type="submit" >Update User</button>
<button type="button" onClick={()=>{
setForm({...userObj})
setEditId('')}}>Reset Update</button>
</>:

<button type="submit" >Create User</button>}
<form className="input-box" onSubmit={handleSaveUserData}>
<input
type="text"
name="name"
value={form.name}
onChange={handleChange}
/>
<input
type="email"
name="email"
value={form.email}
onChange={handleChange}
/>
<input
type="text"
name="city"
value={form.city}
onChange={handleChange}
/>

{isEditId ? (
<>
<button type="submit">Update User</button>
<button
type="button"
onClick={() => {
setForm({ ...userObj });
setEditId("");
}}
>
Reset Update
</button>
</>
) : (
<button type="submit">Create User</button>
)}
</form>

<div className='center-dev'>
{
<table border={1} >
<div className="center-dev">
<table border={1}>
<thead>
<th>Name</th>
<th>Email</th>
<th>City</th>
<th>Date</th>
<th>Action</th>

<tr>
<th>Name</th>
<th>Email</th>
<th>City</th>
<th>Date</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{
status&&data.data.map((el:User)=>
<tr>
<td>{el.name}</td>
<td>{el.email}</td>
<td>{el.city}</td>
<td>{new Date(el.createdAt).toLocaleString()}</td>
<td>
<button onClick={()=>handaleUpdate(el)}>Edit</button>
<button onClick={()=>handaledeleteuserData(el._id)}>Delete</button>
</td>
</tr>
)
}
</tbody>
{status &&
data.data.map((el: User) => (
<tr key={el._id}>
<td>{el.name}</td>
<td>{el.email}</td>
<td>{el.city}</td>
<td>{new Date(el.createdAt).toLocaleString()}</td>
<td>
<button onClick={() => handleUpdate(el)}>Edit</button>
<button onClick={() => handleDeleteUserData(el._id)}>
Delete
</button>
</td>
</tr>
))}
</tbody>
</table>

}
</div>

</div>
</div>
);
}
Expand Down
2 changes: 0 additions & 2 deletions client/src/api/crud.ts → client/src/services/crud.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { useEffect, useState } from "react"
import { CleanUser, UserFetchApi } from "../type/crud"



function useHookGetData():UserFetchApi {
const [data,setData] = useState({status:false,data:[]})
const getDataofUser = async ()=>{
Expand Down
Loading