Understanding React Hooks
React Hooks are functions that let you "hook into" React state and lifecycle features from function components. They were introduced in React 16.8 to allow you to use state and other React features without writing a class.
Hooks provide a more direct API to the React concepts you already know: props, state, context, refs, and lifecycle.
useState Hook
The useState Hook is the most basic Hook that lets you add state to functional components. It returns a stateful value and a function to update it.
Key Points:
- Declares a state variable
- Returns current state and setter function
- Preserves state between re-renders
- Can be used multiple times in a component
Example:
import { 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>
);
}
useEffect Hook
The useEffect Hook lets you perform side effects in function components. It serves the same purpose as componentDidMount, componentDidUpdate, and componentWillUnmount in React classes.
Common Use Cases:
- Data fetching
- Subscriptions
- DOM manipulations
- Setting up event listeners
Example:
import { useState, useEffect } from 'react';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchUser() {
try {
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
setUser(data);
} catch (error) {
console.error('Error fetching user:', error);
} finally {
setLoading(false);
}
}
fetchUser();
}, [userId]); // Only re-run if userId changes
if (loading) return <div>Loading...</div>;
if (!user) return <div>User not found</div>;
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
);
}
useContext Hook
The useContext Hook lets you subscribe to React context without introducing nesting. It accepts a context object and returns the current context value.
When to Use:
- Sharing global state
- Theming
- User preferences
- Authentication state
Example:
import { createContext, useContext } from 'react';
const ThemeContext = createContext('light');
function ThemedButton() {
const theme = useContext(ThemeContext);
return (
<button className={`btn-${theme}`}>
Themed Button
</button>
);
}
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemedButton />
</ThemeContext.Provider>
);
}
useRef Hook
The useRef Hook returns a mutable ref object whose .current property is initialized to the passed argument. It's useful for accessing DOM elements and storing mutable values that don't trigger re-renders.
Common Use Cases:
- Accessing DOM elements
- Storing previous values
- Managing focus, text selection, or media playback
- Triggering imperative animations
Example:
import { useRef, useEffect } from 'react';
function TextInputWithFocusButton() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus();
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={focusInput}>
Focus the input
</button>
</div>
);
}
Hooks Best Practices
1. Only Call Hooks at the Top Level
Don't call Hooks inside loops, conditions, or nested functions. Always use Hooks at the top level of your React function.
2. Only Call Hooks from React Functions
Don't call Hooks from regular JavaScript functions. Only call Hooks from React function components or custom Hooks.
3. Use Multiple useEffect Hooks
Split different concerns into multiple useEffect calls instead of putting all logic in a single useEffect.
4. Clean Up Effects
Always clean up subscriptions, event listeners, and other side effects in the useEffect cleanup function.
Next Steps
Now that you understand React Hooks, you might want to explore: