Mastering React Hooks: Key Hooks and Tips for Functional Components
Shashika Jayathilaka
ASE @elogicLanka | Fullstack Developer | PHP | Laravel | ReactJS | CCNA
As I've been learning React Hooks, I've realized how they simplify working with functional components. Hooks like useState, useEffect, and useRef bring in new features that were once only possible in class components. In this article, I’ll share what I’ve learned about these Hooks, some important rules, and tips for using them efficiently.
Getting Started with React Hooks
Before React Hooks, functional components couldn’t hold or manage state. Only class components could. Now, with Hooks, we can use state and lifecycle methods in functional components, making our code cleaner and more modular.
1. useState Hook: Managing Component State
The useState hook lets us add state to functional components. For example, if we need a name input, we can set up state like this:
const [name, setName] = useState('');
We get two items: the current state (name) and a function to update it (setName). The key difference here is that while regular variables don’t re-render a component when updated, state variables do. That’s why state is so powerful. It keeps the UI in sync with updates. You can even create multiple state variables if needed.
2. useEffect Hook: Handling Side Effects
In class components, we use lifecycle methods like componentDidMount, componentDidUpdate, and componentWillUnmount to manage side effects like data fetching. However, functional components don’t have lifecycle methods. Instead, we use the useEffect hook, which can act like all these lifecycle methods combined.
Here’s a basic example:
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => response.json())
.then(data => setUserList(data));
}, []);
The useEffecthook here does the same job as componentDidMount. It fetches data when the component first loads. The empty array at the end is a dependency array, which controls when useEffect runs. With an empty array, it runs only once, just like componentDidMount.
Updating with Dependencies
We can also use variables inside the dependency array. For example, if we add a variable like count, useEffect will run whenever count changes:
useEffect(() => {
console.log('Effect triggered!');
}, [count]);
In this case, useEffect works like componentDidMount on the first render and like componentDidUpdate whenever count updates. Using dependencies carefully can prevent unnecessary re-renders, which can slow down the app.
领英推荐
3. useRef Hook: Accessing the DOM Directly
useRef is useful when we need to access DOM elements or hold a value that doesn’t require a re-render. For example, if we want to change an element’s color without re-rendering the entire component, we can do this:
const boxRef = useRef();
const changeColor = () => {
boxRef.current.style.backgroundColor = 'teal';
};
This allows us to make changes without causing a re-render. useRef is also ideal for creating stable references that persist across re-renders.
4. Rules of React Hooks
There are a few important rules when using Hooks:
5. Cleanup Functions in useEffect
When using useEffect, we might sometimes want to clean up after certain actions. React allows this by adding a cleanup function. For example, if we’re tracking the mouse position, we can stop tracking it when the component unmounts:
useEffect(() => {
const handleMouseMove = (event) => {
console.log(event.clientX, event.clientY);
};
window.addEventListener('mousemove', handleMouseMove);
return () => {
window.removeEventListener('mousemove', handleMouseMove);
};
}, []);
The return statement here removes the event listener when the component unmounts, preventing any memory leaks.
6. Custom Hooks: Reusing Logic Across Components
One of the most powerful aspects of React Hooks is the ability to create custom hooks. Custom hooks let us reuse logic across multiple components. For instance, I created a simple useForm hook to handle form input:
function useForm(initialValues) {
const [values, setValues] = useState(initialValues);
const handleChange = (e) => {
setValues({
...values,
[e.target.name]: e.target.value,
});
};
return [values, handleChange];
}
Using useForm lets us manage forms more efficiently without rewriting code. Custom hooks also follow the same rules as other hooks, so they should start with "use" and should be called only at the top level.
Conclusion
React Hooks have changed the way we write functional components. With hooks like useState, useEffect, and useRef, we can now add state, manage side effects, and even reuse complex logic through custom hooks in functional components. I hope these examples give you a clear idea of how powerful Hooks can be.
If you're exploring React Hooks or have any questions, feel free to reach out or share your own tips in the comments!