React FAQ: Top 75 Questions
7. Explain the concept of Hooks in React.
React Hooks are functions that let you "hook into" React state and lifecycle features from functional components. Before Hooks (introduced in React 16.8), state and lifecycle methods were exclusive to class components. Hooks enable you to write entire React applications using only functional components, promoting cleaner, more concise, and often more understandable code.
Key Hooks and their purposes:
- `useState`: Allows functional components to manage local state. It returns a stateful value and a function to update it.
- `useEffect`: For performing side effects in functional components. It runs after every render of the component by default, but its behavior can be controlled with a dependency array (e.g., `[]` for mount/unmount, `[dep]` for changes in `dep`). It can also return a cleanup function.
- `useContext`: To consume context, making it easier to share values (like themes or authenticated user data) across the component tree without prop-drilling.
- `useReducer`: An alternative to `useState` for more complex state logic, especially when state transitions depend on previous state or involve multiple sub-values. It's often used with `useContext` for global state management.
- `useCallback`: Memoizes a callback function, preventing unnecessary re-creation of functions on re-renders, which can help optimize performance in child components that rely on reference equality.
- `useMemo`: Memoizes a computed value, recalculating it only when its dependencies change, thus avoiding expensive calculations on every render.
- `useRef`: Returns a mutable ref object whose `.current` property is initialized to the passed argument and can be used to access DOM elements or persist mutable values across renders without causing a re-render.
Hooks follow two strict rules:
- Only Call Hooks at the Top Level: Don't call Hooks inside loops, conditions, or nested functions.
- Only Call Hooks from React Functions: Call them from React functional components or custom Hooks.
import React, { useState, useEffect, useContext, createContext, useRef } from 'react';
import ReactDOM from 'react-dom/client';
// 1. useState Hook
function Counter() {
const [count, setCount] = useState(0); // count: state, setCount: setter
return (
<div>
<h3>useState Demo</h3>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
// 2. useEffect Hook
function DataFetcher() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
console.log('useEffect: Fetching data...');
// Simulate API call
const timer = setTimeout(() => {
setData({ message: 'Data fetched successfully!' });
setLoading(false);
}, 2000);
// Cleanup function (runs on unmount or before next effect run)
return () => {
console.log('useEffect: Cleaning up timeout...');
clearTimeout(timer);
};
}, []); // Empty array means run once on mount and cleanup on unmount
return (
<div>
<h3>useEffect Demo</h3>
{loading ? <p>Loading data...</p> : <p>{data.message}</p>}
</div>
);
}
// 3. useContext Hook
const ThemeContext = createContext('light'); // Default value is 'light'
function ThemeButton() {
const theme = useContext(ThemeContext); // Consume the context value
return (
<div>
<h3>useContext Demo</h3>
<button style={{ background: theme === 'dark' ? '#333' : '#eee', color: theme === 'dark' ? '#eee' : '#333' }}>
Current Theme: {theme}
</button>
</div>
);
}
// 4. useRef Hook
function TextInputWithFocusButton() {
const inputRef = useRef(null); // Create a ref object
const focusInput = () => {
inputRef.current.focus(); // Access the DOM element
};
return (
<div>
<h3>useRef Demo</h3>
<input type="text" ref={inputRef} /> {/* Attach the ref to the input */}
<button onClick={focusInput}>Focus Input</button>
</div>
);
}
function App() {
return (
<div>
<Counter />
<hr />
<DataFetcher />
<hr />
<ThemeContext.Provider value="dark"> {/* Provide a value for context */}
<ThemeButton />
</ThemeContext.Provider>
<hr />
<TextInputWithFocusButton />
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('root-hooks'));
root.render(<App />);
Explanation of the Code:
- **`Counter` (`useState`):** Demonstrates basic state management. `count` holds the current value, and `setCount` is the function to update it, triggering a re-render.
- **`DataFetcher` (`useEffect`):** Shows how to perform side effects. The `useEffect` runs once on mount (due to `[]` dependency). It simulates an API call with `setTimeout` and cleans up the timer on unmount (via the return function).
- **`ThemeButton` (`useContext`):** Shows how a component can consume a value provided by a `Context.Provider` higher up in the component tree, avoiding prop drilling.
- **`TextInputWithFocusButton` (`useRef`):** Illustrates accessing a DOM element directly. `inputRef` is attached to the input field, allowing the `focusInput` function to call the `.focus()` method on the actual DOM element.
Hooks provide a powerful and flexible way to add state and lifecycle logic to functional components, leading to more modular and readable React code.