Mastering React Hooks: A Practical Tutorial

Tomas Gabrs
4 min readNov 5, 2023

--

React has evolved significantly over the years, and one of the most revolutionary changes came with the introduction of React Hooks. As a junior developer, you might find hooks a bit daunting at first, but with the right guidance, you can master them in no time. In this article, I’ll be your guide, and we’ll dive into React Hooks with a series of questions from Bob, a junior developer, and answers from Tom, a senior developer.

Bob: What are React Hooks, and why are they important?

Tom: React Hooks are functions that let you “hook into” React state and lifecycle features from functional components. They were introduced in React 16.8 to allow functional components to have state and side effects, which were previously only possible with class components.

import { useState, useEffect } from 'react';

function ExampleComponent() {
const [count, setCount] = useState(0);

useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);

return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}

Bob: What’s the difference between useState and useEffect?

Tom: useState is a hook used for managing state, while useEffect is for handling side effects like data fetching, DOM manipulation, and more. The second argument of useEffect is an array of dependencies that controls when the effect runs.

Bob: Can you explain the use of the useEffect dependency array?

Tom: The dependency array in useEffect allows you to specify which variables or props the effect depends on. When these dependencies change, the effect is re-executed. This can be helpful to optimize performance and prevent unnecessary re-renders.

useEffect(() => {
// This effect will run whenever 'count' changes.
// You can have multiple dependencies in the array.
}, [count]);

Bob: How do I create a custom Hook?

Tom: You can create custom hooks by extracting and reusing stateful logic across components. Simply create a function starting with “use,” and inside, you can use other built-in hooks or your custom hooks.

// Custom hook for handling window dimensions
function useWindowSize() {
const [windowSize, setWindowSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
});

useEffect(() => {
function handleResize() {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
}

window.addEventListener('resize', handleResize);

return () => {
window.removeEventListener('resize', handleResize);
};
}, []);

return windowSize;
}

Bob: What is the purpose of the useRef hook?

Tom: useRef is used to create mutable references to DOM elements or other values that persist between renders. It's often used for accessing and modifying DOM elements directly.

import { useRef, useEffect } from 'react';

function TextInputWithFocusButton() {
const inputRef = useRef(null);

const focusInput = () => {
inputRef.current.focus();
};

useEffect(() => {
focusInput(); // Focus the input element on component mount.
}, []);

return (
<div>
<input ref={inputRef} />
<button onClick={focusInput}>Focus Input</button>
</div>
);
}

Bob: How do I handle form inputs using hooks?

Tom: You can use the useState hook to manage form input values and update them as the user interacts with the form.

import { useState } from 'react';

function FormInput() {
const [inputValue, setInputValue] = useState('');

const handleInputChange = (e) => {
setInputValue(e.target.value);
};

return (
<input
type="text"
value={inputValue}
onChange={handleInputChange}
placeholder="Enter text"
/>
);
}

Bob: How can I share state between components using hooks?

Tom: You can use a combination of useState, useEffect, and Context API to share state between components. Context API allows you to provide a value to all descendants without manually passing props through each level.

Bob: What’s the purpose of the useMemo and useCallback hooks?

Tom: useMemo is used to memoize the result of a computation, while useCallback memoizes callback functions. This can help optimize performance by preventing unnecessary re-renders.

import { useState, useMemo, useCallback } from 'react';

function ExpensiveComponent({ data }) {
const processData = useMemo(() => expensiveComputation(data), [data]);
const handleClick = useCallback(() => doSomethingWithProcessedData(processData), [processData]);

return (
<div>
<p>{processData}</p>
<button onClick={handleClick}>Process Data</button>
</div>
);
}

Bob: What are the limitations of using hooks?

Tom: Hooks are a powerful addition to React, but there are some limitations. For instance, they can’t be conditionally called, and they must be used at the top level of your functional component. Make sure you read the official documentation to understand these limitations.

Bob: How can I test components using hooks?

Tom: You can test components using hooks by utilizing testing libraries like Jest and React Testing Library. These libraries provide utilities for rendering components, interacting with them, and asserting the expected behavior.

React Hooks have transformed the way we build React applications. With the practical insights provided in this article, you can accelerate your learning curve and become proficient in using hooks to manage state and side effects in your functional components. Remember, practice and experimentation are key to mastering React Hooks, so keep building and learning!

--

--

Tomas Gabrs

Senior software developer with 7+ years of experience, deeply committed to frontend development, on a lifelong journey of learning and sharing knowledge.