Hooks in React
Hooks are functions that let you use state and lifecycle features in functional components. Introduced in React 16.8, they eliminate the need for class components in most cases.
Common Hooks
useState
Manages local component state.
Key Points
Returns current state and a setter function
State updates trigger re-render
State is preserved across renders
Code Example
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
export default Counter;
useEffect
Handles side effects such as API calls, subscriptions, or DOM updates.
Key Points
Runs after render
Can depend on specific variables
Can return a cleanup function
Code Example
import { useEffect, useState } from "react";
function DataFetcher() {
const [data, setData] = useState([]);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/posts")
.then((res) => res.json())
.then((data) => setData(data));
}, []);
return (
<ul>
{data.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>
);
}
useContext
Allows access to global state without prop drilling.
Code Example
import { createContext, useContext } from "react";
const ThemeContext = createContext("light");
function Child() {
const theme = useContext(ThemeContext);
return <p>Theme: {theme}</p>;
}
function App() {
return (
<ThemeContext.Provider value="dark">
<Child />
</ThemeContext.Provider>
);
}
useRef
Persists values across renders without causing re-renders.
Code Example
import { useRef } from "react";
function InputFocus() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus();
};
return (
<>
<input ref={inputRef} />
<button onClick={focusInput}>Focus</button>
</>
);
}
Rules of Hooks
Call hooks only at the top level
Do not call hooks inside loops, conditions, or nested functions
Only call hooks from React functions
Conditional Rendering
Conditional rendering allows components to render different UI elements based on conditions.
Techniques
if Statement
function Greeting({ isLoggedIn }) {
if (isLoggedIn) {
return <h1>Welcome back</h1>;
}
return <h1>Please log in</h1>;
}
Ternary Operator
function Greeting({ isLoggedIn }) {
return (
<h1>{isLoggedIn ? "Welcome back" : "Please log in"}</h1>
);
}
Logical AND (&&)
function Notification({ hasMessage }) {
return (
<div>
{hasMessage && <p>You have new messages</p>}
</div>
);
}
Conditional Rendering with Variables
function Status({ isOnline }) {
let message;
if (isOnline) {
message = "User is online";
} else {
message = "User is offline";
}
return <p>{message}</p>;
}
Lifting State Up
Overview
Lifting state up means moving shared state to the closest common parent so multiple components can access and synchronize it.
When to Use
When two or more components need the same data
When sibling components need to communicate
To maintain a single source of truth
Example Without Lifting State
function InputA() {
const [text, setText] = useState("");
return <input value={text} onChange={(e) => setText(e.target.value)} />;
}
function InputB() {
const [text, setText] = useState("");
return <input value={text} onChange={(e) => setText(e.target.value)} />;
}
Problem: States are independent and not synchronized.
Example With Lifting State Up
import { useState } from "react";
function Parent() {
const [text, setText] = useState("");
return (
<>
<InputA text={text} setText={setText} />
<InputB text={text} setText={setText} />
</>
);
}
function InputA({ text, setText }) {
return <input value={text} onChange={(e) => setText(e.target.value)} />;
}
function InputB({ text, setText }) {
return <input value={text} onChange={(e) => setText(e.target.value)} />;
}