useState:
Purpose: To manage state within a functional component.
Usage: const [state, setState] = useState(initialValue);
Explanation: useState
returns an array with two elements: the current state value and a function to update that state. When you call the updater function, React will re-render the component with the updated state.
Example:
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
)
useEffect:
Purpose: To handle side effects in functional components, such as data fetching, subscriptions, or manually changing the DOM.
Usage: useEffect(() => { /* side effect code */ }, [dependencies]);
Explanation: useEffect
runs after every render by default. The optional second argument, an array of dependencies, determines when the effect should re-run. If the dependencies don’t change, the effect won't re-run.
Example:
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes
useContext:
Purpose: To access the context value in a functional component.
Usage: const value = useContext(SomeContext);
Explanation: useContext
allows you to consume a context directly without needing to wrap your component in a Consumer component. It simplifies the way you work with React Context.
Example:
const theme = useContext(ThemeContext);
return <button style={{ background: theme.background }}>Click me</button>;
useReducer:
Purpose: To manage more complex state logic in your component, as an alternative to useState
.
Usage: const [state, dispatch] = useReducer(reducer, initialState);
Explanation: useReducer
is similar to useState
but is more suitable when you have complex state logic involving multiple sub-values or when the next state depends on the previous one. It accepts a reducer function and an initial state, returning the current state and a dispatch function.
Example:
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
Count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
);
useMemo:
Purpose: To optimize performance by memoizing expensive computations.
Usage: const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
Explanation: useMemo
only re-computes the memoized value when one of its dependencies changes. This can help to avoid expensive calculations on every render.
Example:
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
useCallback:
Purpose: To memoize functions so that they do not get re-created on every render.
Usage: const memoizedCallback = useCallback(() => { /* callback */ }, [dependencies]);
Explanation: useCallback
returns a memoized version of the callback function that only changes if one of the dependencies has changed. This is useful when passing callbacks to child components that rely on reference equality to prevent unnecessary renders.
Example:
const handleClick = useCallback(() => {
console.log('Button clicked');
}, []); // Memoize handleClick
return <button onClick={handleClick}>Click me</button>;
useRef:
Purpose: To create a mutable object that persists across renders, often used for accessing DOM elements directly or storing mutable values.
Usage: const ref = useRef(initialValue);
Explanation: useRef
returns a mutable ref
object whose .current
property is initialized to the passed argument (initialValue
). This object persists throughout the component's lifecycle, and updates to .current
do not trigger re-renders.
Example:
const inputEl = useRef(null);
const handleFocus = () => {
inputEl.current.focus();
};
return (
<div>
<input ref={inputEl} type="text" />
<button onClick={handleFocus}>Focus the input</button>
</div>
);
Hooks allow you to use state and other React features without writing a class. They enable you to organize the logic inside a component by splitting it into reusable pieces, called Hooks, rather than dividing it by lifecycle methods.
You can create your own Hooks to encapsulate and reuse logic across different components. Custom Hooks are just regular functions that can use other Hooks.
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return width;
}
// Usage in a component
function Component() {
const width = useWindowWidth();
return <div>Window width is: {width}</div>;
}