What are Hooks in React with TypeScript?
Hooks are functions that let you "hook into" React state and lifecycle features from function components. In TypeScript, hooks are strongly typed to provide better developer experience and type safety.
Core React Hooks:
useState - Manages component state
useEffect - Handles side effects
useContext - Accesses context values
useReducer - Manages complex state logic
useCallback - Memoizes functions
useMemo - Memoizes values
useRef - Creates mutable references
useLayoutEffect - Similar to useEffect but fires synchronously after DOM mutations
Why Use Hooks in React with TypeScript?
1. Type Safety
TypeScript adds static typing to hooks, catching errors at compile time:
2. Better Organization
Hooks allow you to organize logic by concern rather than lifecycle:
3. Reusable Logic
Custom hooks encapsulate and share logic across components:
AddEmployee.tsx component
Imports Section
import React, { useState, useEffect, ChangeEvent, FormEvent } from "react"; // React core imports including hooks and event types import axios from "axios"; // HTTP client for making API requests import { Form, Button, Container, Alert } from "react-bootstrap"; // Bootstrap components for UI import { useNavigate, Link } from "react-router-dom"; // Routing utilities for navigation import Header from "../components/Header"; // Custom header component import { Employee } from "../models/Employee"; import { Department } from "../models/Department"; // Type definitions for Employee and Department
Interface Definition
interface ValidationErrors { [key: string]: string; } // Defines a type for validation errors where keys are strings and values are error messages
Component Definition
const AddEmployee: React.FC = () => { // Main component definition as a Function Component
State Management
const [employee, setEmployee] = useState<Employee>({ empId: 0, empName: "", designation: "", dateOfJoining: "", salary: 0, empPhoneNumber: "", isActive: true, deptId: 0 }); // State for employee form data, initialized with default values const [departments, setDepartments] = useState<Department[]>([]); // State for storing department list fetched from API const [error, setError] = useState<string>(""); // State for general error messages const [validationErrors, setValidationErrors] = useState<ValidationErrors>({}); // State for form validation errors const navigate = useNavigate(); // Hook for programmatic navigation
API Configuration
const EMPLOYEE_API_URL = "http://localhost:9090/api/employees"; const DEPARTMENT_API_URL = "http://localhost:9090/api/departments"; // API endpoint URLs
Effect Hook for Data Fetching
useEffect(() => { const fetchDepartments = async () => { try { const response = await axios.get<Department[]>(DEPARTMENT_API_URL); setDepartments(response.data); } catch (error) { console.error("Error fetching departments:", error); setError("Failed to load departments."); } }; fetchDepartments(); }, []); // Fetches departments on component mount and stores them in state
Form Validation
const validateForm = (): boolean => { const errors: ValidationErrors = {}; if (!employee.empName.trim()) errors.empName = "Name is required."; if (!employee.designation.trim()) errors.designation = "Designation is required."; if (!employee.dateOfJoining) errors.dateOfJoining = "Date of Joining is required."; if (employee.salary <= 0) errors.salary = "Salary must be greater than 0."; if (!employee.empPhoneNumber.trim()) { errors.empPhoneNumber = "Phone Number is required."; } else if (!/^\d{10}$/.test(employee.empPhoneNumber)) { errors.empPhoneNumber = "Phone Number must be 10 digits."; } if (!employee.deptId) errors.deptId = "Department is required."; setValidationErrors(errors); return Object.keys(errors).length === 0; }; // Validates form fields and returns true if all validations pass
Form Submission Handler
const handleSubmit = async (e: FormEvent) => { e.preventDefault(); if (!validateForm()) return; try { const response = await axios.post(EMPLOYEE_API_URL, employee); if (response.status === 200 || response.status === 201) { navigate("/"); } } catch (error) { setError("Error adding employee. Please try again."); console.error("Error adding employee:", error); } }; // Handles form submission, validates, sends data to API, and navigates on success
Input Change Handlers
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { const { name, value, type } = e.target; setEmployee((prev) => ({ ...prev, [name]: type === "number" ? Number(value) : value, })); setValidationErrors((prev) => ({ ...prev, [name]: "", })); }; // Handles changes for input fields, converts to number if needed, clears validation errors const handleSelectChange = (e: React.ChangeEvent<HTMLSelectElement>) => { const { name, value } = e.target; setEmployee((prev) => ({ ...prev, [name]: Number(value), })); setValidationErrors((prev) => ({ ...prev, [name]: "", })); }; // Handles changes for select fields, converts value to number, clears validation errors
User Data (Hardcoded for Demo)
const user = "Sanjay"; // Hardcoded user name for demo purposes
JSX Rendering
return ( <div className="container-fluid mt-4"> <div className="card shadow p-4"> <Header loginName={user} /> <Container> <div className="d-flex justify-content-between align-items-center mb-4"> <h1>Add Employee</h1> <Link to="/" className="btn btn-secondary"> <i className="fas fa-arrow-left"></i> Employees List </Link> </div> {error && <Alert variant="danger">{error}</Alert>} <Form onSubmit={handleSubmit}> {/* Form fields for each employee property */} {/* Each field includes validation feedback */} {/* Name Field */} <Form.Group className="mb-3"> <Form.Label>Name</Form.Label> <Form.Control type="text" name="empName" value={employee.empName} onChange={handleInputChange} isInvalid={!!validationErrors.empName} /> <Form.Control.Feedback type="invalid"> {validationErrors.empName} </Form.Control.Feedback> </Form.Group> {/* Other form fields follow similar pattern */} {/* Designation, Date of Joining, Salary, Phone, Department, Active Status */} {/* Submit Button */} <Button variant="primary" type="submit"> Save Employee </Button> </Form> </Container> </div> </div> ); }; export default AddEmployee;
Key Features:
Type Safety: Uses TypeScript interfaces for Employee and Department
Form Validation: Client-side validation with clear error messages
API Integration: Fetches departments and posts new employee data
Error Handling: Catches and displays API errors
Routing: Uses React Router for navigation
Bootstrap UI: Clean, responsive form layout with Bootstrap components
State Management: Uses React hooks for all state needs
Modular Design: Separates concerns with clear component structure