React Performance

React Performance Optimization Techniques

Performance is a crucial factor in React application development. In this article, we’ll explore techniques and best practices to optimize performance. 1. React.memo() React.memo() helps prevent unnecessary re-renders: import React, { memo } from "react"; const ExpensiveComponent = memo(({ data }) => { console.log("Component rendered"); return ( <div> <h2>{data.title}</h2> <p>{data.description}</p> </div> ); }); // Component only re-renders when props change export default ExpensiveComponent; 2. useMemo Hook Use useMemo for expensive calculations: import React, { useMemo } from "react"; function ProductList({ products, searchTerm }) { const filteredProducts = useMemo(() => { return products.filter((product) => product.name.toLowerCase().includes(searchTerm.toLowerCase()), ); }, [products, searchTerm]); const expensiveCalculation = useMemo(() => { return filteredProducts.reduce((sum, product) => sum + product.price, 0); }, [filteredProducts]); return ( <div> <p>Total Price: {expensiveCalculation}</p> {filteredProducts.map((product) => ( <div key={product.id}> {product.name} - ${product.price} </div> ))} </div> ); } 3. useCallback Hook Optimize event handlers: ...

January 20, 2024 · 3 min · Nguyen Hoang Diep Phi
React Hooks

Learning React Hooks: From Basics to Advanced

React Hooks have revolutionized how we write React components. In this article, we’ll explore basic hooks and how to apply them in real-world projects. Basic Hooks 1. useState Hook useState is the most basic hook, helping manage state in functional components: import React, { useState } from "react"; function Counter() { const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}>Click me</button> </div> ); } 2. useEffect Hook useEffect replaces lifecycle methods in class components: ...

January 15, 2024 · 3 min · Nguyen Hoang Diep Phi
TypeScript

TypeScript in React: Best Practices

TypeScript brings type safety to React applications. Let’s explore how to use TypeScript effectively in React projects. Defining Props Interface interface ButtonProps { text: string; onClick: () => void; variant?: "primary" | "secondary"; disabled?: boolean; } const Button: React.FC<ButtonProps> = ({ text, onClick, variant = "primary", disabled = false, }) => { return ( <button className={`btn btn-${variant}`} onClick={onClick} disabled={disabled} > {text} </button> ); }; State Management with TypeScript useState with Types import React, { useState } from "react"; interface User { id: number; name: string; email: string; } const UserProfile: React.FC = () => { const [user, setUser] = useState<User | null>(null); const [loading, setLoading] = useState<boolean>(false); const fetchUser = async (id: number) => { setLoading(true); try { const response = await fetch(`/api/users/${id}`); const userData: User = await response.json(); setUser(userData); } catch (error) { console.error("Error fetching user:", error); } finally { setLoading(false); } }; return ( <div> {loading ? ( <p>Loading...</p> ) : user ? ( <div> <h1>{user.name}</h1> <p>{user.email}</p> </div> ) : ( <p>No user data</p> )} </div> ); }; useReducer with TypeScript import React, { useReducer } from "react"; interface TodoState { todos: Todo[]; filter: "all" | "completed" | "active"; } interface Todo { id: number; text: string; completed: boolean; } type TodoAction = | { type: "ADD_TODO"; payload: string } | { type: "TOGGLE_TODO"; payload: number } | { type: "SET_FILTER"; payload: TodoState["filter"] }; const todoReducer = (state: TodoState, action: TodoAction): TodoState => { switch (action.type) { case "ADD_TODO": return { ...state, todos: [ ...state.todos, { id: Date.now(), text: action.payload, completed: false }, ], }; case "TOGGLE_TODO": return { ...state, todos: state.todos.map((todo) => todo.id === action.payload ? { ...todo, completed: !todo.completed } : todo, ), }; case "SET_FILTER": return { ...state, filter: action.payload, }; default: return state; } }; Event Handling import React, { ChangeEvent, FormEvent } from "react"; const ContactForm: React.FC = () => { const [formData, setFormData] = useState({ name: "", email: "", message: "", }); const handleInputChange = ( e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>, ) => { const { name, value } = e.target; setFormData((prev) => ({ ...prev, [name]: value, })); }; const handleSubmit = (e: FormEvent<HTMLFormElement>) => { e.preventDefault(); console.log("Form submitted:", formData); }; return ( <form onSubmit={handleSubmit}> <input type="text" name="name" value={formData.name} onChange={handleInputChange} placeholder="Your name" /> <input type="email" name="email" value={formData.email} onChange={handleInputChange} placeholder="Your email" /> <textarea name="message" value={formData.message} onChange={handleInputChange} placeholder="Your message" /> <button type="submit">Send</button> </form> ); }; Generic Components interface ListProps<T> { items: T[]; renderItem: (item: T) => React.ReactNode; keyExtractor: (item: T) => string | number; } function List<T>({ items, renderItem, keyExtractor }: ListProps<T>) { return ( <ul> {items.map((item) => ( <li key={keyExtractor(item)}>{renderItem(item)}</li> ))} </ul> ); } // Usage const users: User[] = [ { id: 1, name: "John", email: "john@example.com" }, { id: 2, name: "Jane", email: "jane@example.com" }, ]; <List items={users} renderItem={(user) => ( <span> {user.name} ({user.email}) </span> )} keyExtractor={(user) => user.id} />; Custom Hooks with TypeScript import { useState, useEffect } from "react"; interface FetchState<T> { data: T | null; loading: boolean; error: string | null; } function useFetch<T>(url: string): FetchState<T> { const [state, setState] = useState<FetchState<T>>({ data: null, loading: true, error: null, }); useEffect(() => { const fetchData = async () => { try { setState((prev) => ({ ...prev, loading: true })); const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data: T = await response.json(); setState({ data, loading: false, error: null }); } catch (error) { setState({ data: null, loading: false, error: error instanceof Error ? error.message : "An error occurred", }); } }; fetchData(); }, [url]); return state; } Best Practices 1. Use Strict TypeScript Configuration // tsconfig.json { "compilerOptions": { "strict": true, "noImplicitAny": true, "noImplicitReturns": true, "noUnusedLocals": true, "noUnusedParameters": true } } 2. Prefer Type over Interface for Unions // Good for unions type Status = "loading" | "success" | "error"; // Good for object shapes interface User { id: number; name: string; email: string; } 3. Use Utility Types // Partial for optional properties const updateUser = (id: number, updates: Partial<User>) => { // Implementation }; // Pick for selecting specific properties type UserPreview = Pick<User, "id" | "name">; // Omit for excluding properties type CreateUserRequest = Omit<User, "id">; Conclusion TypeScript significantly improves the React development experience by providing: ...

January 10, 2024 · 4 min · Nguyen Hoang Diep Phi