Introduction:
ReactJS hooks have transformed the way developers handle state and side effects in React functional components. In this blog, we’ll delve into each ReactJS hook, providing clear explanations and practical examples to demonstrate their usage and benefits.
1. useState:
useState allows functional components to manage local state.
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
2. useEffect:
useEffect enables performing side effects in functional components, such as data fetching, subscriptions, or manually changing the DOM.
Example:
import React, { useState, useEffect } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const intervalId = setInterval(() => {
setSeconds(seconds + 1);
}, 1000);
return () => clearInterval(intervalId);
}, [seconds]);
return <p>Seconds: {seconds}</p>;
}
3. useContext:
useContext provides a way to access context in functional components, enabling the propagation of values like themes, user preferences, or localization preferences throughout the component tree.
Example:
import React, { useContext } from 'react';
const ThemeContext = React.createContext('light');
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button style={{ background: theme }}>Themed Button</button>;
}
4. useReducer:
useReducer is an alternative to useState, primarily used for managing complex state logic in functional components. It accepts a reducer function with the current state and an action to perform, returning the new state.
Example:
import React, { useReducer } from 'react';
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();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
Count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
);
}
5. useCallback:
useCallback memoizes functions, preventing unnecessary re-renders in child components when the function reference remains the same.
Example:
import React, { useState, useCallback } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
const increment = useCallback(() => setCount(count + 1), [count]);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
6. useMemo:
useMemo memoizes expensive computations, recalculating the value only when the dependencies change.
Example:
import React, { useMemo } from 'react';
function ExpensiveCalculation({ count }) {
const result = useMemo(() => {
return count * 2;
}, [count]);
return <p>Result: {result}</p>;
}
7. useRef:
useRef creates a mutable ref object whose .current property can hold a value, persisting across renders.
Example:
import React, { useRef } from 'react';
function TextInputWithFocusButton() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus();
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={focusInput}>Focus Input</button>
</div>
);
}
8. useImperativeHandle:
useImperativeHandle customizes the instance value that is exposed to parent components when using forwardRef.
Example:
import React, { useRef, useImperativeHandle, forwardRef } from 'react';
const FancyInput = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} />;
});
function ParentComponent() {
const fancyInputRef = useRef();
const focusInput = () => {
fancyInputRef.current.focus();
};
return (
<div>
<FancyInput ref={fancyInputRef} />
<button onClick={focusInput}>Focus Input</button>
</div>
);
}
10. useDebugValue:
useDebugValue provides a way to display a label for custom hooks in React DevTools, improving the debugging experience.
Example:
import React, { useState, useDebugValue } from 'react';
function useCustomHook() {
const [count, setCount] = useState(0);
useDebugValue(count > 5 ? 'Count is greater than 5' : 'Count is less than or equal to 5');
return [count, setCount];
}
Conclusion:
ReactJS hooks offer a powerful way to manage state, side effects, and other aspects of functional components in React applications. By mastering these hooks and understanding their nuances, developers can write cleaner, more efficient, and more maintainable code. Experiment with the examples provided to deepen your understanding and unlock the full potential of ReactJS hooks in your projects.