10 Essential React Hooks You Should Know
React has become a cornerstone of modern web development, and with it comes a set of powerful hooks that can simplify your code and enhance your applications. Hooks allow you to manage state, side effects, and other React features without writing class components. In this post, we'll explore ten essential hooks you should know to elevate your React skills.
1. useState
The useState
hook allows you to add state to functional components. It returns a stateful value and a function to update it.typescriptSkopiuj kod
tsx
import React, { useState } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
2. useEffect
The useEffect
hook lets you perform side effects in functional components, such as data fetching or directly manipulating the DOM.
tsx
import React, { useEffect, useState } from 'react';
const DataFetcher = () => {
const [data, setData] = useState(null);
useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => setData(data));
}, []); // Empty dependency array to run only once
return <div>{data ? JSON.stringify(data) : 'Loading...'}</div>;
};
3. useContext
The useContext
hook allows you to access the context directly without using a Consumer component. This makes it easier to manage global state.
tsx
import React, { createContext, useContext } from 'react';
const ThemeContext = createContext('light');
const ThemedComponent = () => {
const theme = useContext(ThemeContext);
return <div className={theme}>Current theme: {theme}</div>;
};
4. useReducer
The useReducer
hook is an alternative to useState
for managing complex state logic. It’s particularly useful when the next state depends on the previous one.
tsx
import React, { useReducer } from 'react';
type State = { count: number };
type Action = { type: 'increment' | 'decrement' };
const reducer = (state: State, action: Action): State => {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
return state;
}
};
const Counter = () => {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
<button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
</div>
);
};
5. useMemo
The useMemo
hook helps optimize performance by memoizing the result of a computation. This can prevent expensive calculations on every render.
tsx
import React, { useMemo } from 'react';
const ExpensiveCalculation = ({ number }) => {
const computedValue = useMemo(() => {
// Expensive calculation
return number * 2;
}, [number]);
return <div>Computed Value: {computedValue}</div>;
};
6. useCallback
The useCallback
hook returns a memoized callback function, which is useful to avoid unnecessary re-renders when passing callbacks to child components.
tsx
import React, { useCallback } from 'react';
const Button = React.memo(({ onClick }) => (
<button onClick={onClick}>Click me</button>
));
const ParentComponent = () => {
const handleClick = useCallback(() => {
console.log('Button clicked!');
}, []);
return <Button onClick={handleClick} />;
};
7. useRef
The useRef
hook allows you to persist a mutable value across renders without causing a re-render. It's great for accessing DOM elements or keeping a mutable reference.
tsx
import React, { useEffect, useRef } from 'react';
const Timer = () => {
const timerId = useRef<NodeJS.Timeout | null>(null);
useEffect(() => {
timerId.current = setInterval(() => {
console.log('Running interval...');
}, 1000);
return () => clearInterval(timerId.current!);
}, []);
return <div>Timer is running</div>;
};
8. useImperativeHandle
The useImperativeHandle
hook customizes the instance value that is exposed to parent components when using ref. It works with forwardRef
tsx
import React, { useImperativeHandle, forwardRef, useRef } from 'react';
const Child = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
alertName: () => {
alert('Hello from Child!');
},
}));
return <div>Child Component</div>;
});
const Parent = () => {
const childRef = useRef();
const handleAlert = () => {
if (childRef.current) {
childRef.current.alertName();
}
};
return (
<div>
<Child ref={childRef} />
<button onClick={handleAlert}>Alert Child Name</button>
</div>
);
};
9. useLayoutEffect
The useLayoutEffect
hook is similar to useEffect
but it runs synchronously after all DOM mutations. It's useful for reading layout from the DOM and synchronously re-rendering.
tsx
import React, { useLayoutEffect, useRef } from 'react';
const LayoutEffectExample = () => {
const divRef = useRef<HTMLDivElement>(null);
useLayoutEffect(() => {
if (divRef.current) {
console.log('Height of the div:', divRef.current.getBoundingClientRect().height);
}
}, []);
return <div ref={divRef}>This is a div</div>;
};
10. useDebugValue
The useDebugValue
hook is used to display a label for custom hooks in React DevTools. It's mainly for debugging purposes.
tsx
import { useDebugValue } from 'react';
function useMyCustomHook(value: number) {
useDebugValue(value > 0 ? 'Positive' : 'Negative');
// Custom logic here
}
Conclusion
Mastering React hooks involves understanding how and when to use them effectively. By integrating these ten essential hooks into your development toolkit, you can write cleaner, more efficient, and more maintainable code. Start implementing these hooks in your projects and watch your React skills soar!