React Hooks is a revolutionary feature introduced in React version 16.8 that allows you to use state and other React features without writing class components. This innovation not only simplifies component logic, but also makes code more reusable and easier to understand.
In this article, we will explore the use of React Hooks from the beginning to the end and guide you on how to customize Hooks to further improve development efficiency and code quality.
React Hook
1. Background to the creation of Hook
Before the advent of Hooks, React applications relied heavily on class components to manage state and lifecycle methods. However, as application complexity increased, maintenance of class components became increasingly difficult, especially when multiple components needed to share state or logic.The React team therefore introduced Hooks, which were designed to address issues such as state management, decentralized lifecycle functions, and logic reuse.
2. Hook rules
There are two basic rules to follow when using Hooks:
Call Hooks only from within function components or custom Hooks. do not call them from within regular JavaScript functions.
Call Hook at the top level of the React function component. do not call Hook in loops, conditional judgments, or nested functions.
3. Why Hooks
Let’s look at two of the most commonly used Hooks to see what it does:
useState: this is the most basic state hook provided by React. it returns a pair of values: the current state and a function to update the state. useState: React uses an internal scheduling mechanism to make sure that state updates are asynchronous, which can help with performance optimizations such as batch updating.Here’s an example: batch update count after button presses
The code is as follows:
import { useState } from 'react';
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>start</h1>
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}
function MyButton({ count, onClick }) {
return (
<button onClick={onClick}>
{count}
</button>
);
}
useEffect: is used to handle side effects such as data fetching, subscription, or manual DOM modification. It takes two arguments: a function that executes the side effect, and a dependency array that determines when to re-execute the side effect, which React executes after the component has been rendered and before the browser finishes drawing.import { useState, useEffect } from 'react'; export default function Counter() { const [count, setCount] = useState(0); useEffect(() => { const intervalId = setInterval(() => { setCount(c => c + 1); }, 1000); return () => clearInterval(intervalId); }, []); return <h1>{count}</h1>; }
4. Hook implementation mechanism
React keeps track of the order and state of each hook call by maintaining a “hook call stack”. Each time a component is rendered, React traverses this call stack to ensure that the order in which the Hooks are called remains consistent, so that the internal state of each Hook is restored correctly. This is why you can’t call a Hook in a conditional statement or a loop – it would break the consistency of the call order.
Custom Hooks
A custom Hook is a way to share reusable logic. It’s just a regular JavaScript function, but its name starts with use
, indicating that it’s meant to be used with other Hooks.
How to Create a Custom Hook
Suppose we want to create a custom Hook to manage complex form state, including validation and submission processing.
import { useState } from 'react';
// Hook: useForm
function useForm(initialValues, validate) {
const [values, setValues] = useState(initialValues);
const [errors, setErrors] = useState({});
function handleChange(e) {
const { name, value } = e.target;
setValues(prev => ({ ...prev, [name]: value }));
}
function validateForm() {
const validationErrors = validate(values);
setErrors(validationErrors);
return Object.keys(validationErrors).length === 0;
}
return {
values,
errors,
handleChange,
validateForm
};
}
export default useForm;
Using a Custom Hook
Next, use the useForm
Hook created above in the component that needs to manage the form.
import React, { useState } from 'react';
import useForm from './useForm';
function MyForm() {
const initialVals = { username: '', email: '' };
const validate = (values) => {
let errors = {};
if (!values.username) errors.username = 'Username is required.';
if (!values.email) errors.email = 'Email is required.';
return errors;
};
const { values, errors, handleChange, validateForm } = useForm(initialVals, validate);
const handleSubmit = (e) => {
e.preventDefault();
if (validateForm()) {
console.log('Form submitted:', values);
}
};
return (
<form onSubmit={handleSubmit}>
<div>
<label>Username:</label>
<input type="text" name="username" onChange={handleChange} value={values.username} />
{errors.username && <span>{errors.username}</span>}
</div>
<div>
<label>Email:</label>
<input type="email" name="email" onChange={handleChange} value={values.email} />
{errors.email && <span>{errors.email}</span>}
</div>
<button type="submit">Submit</button>
</form>
);
}
export default MyForm;
React Hooks provide a completely new way to build components, dramatically improving code readability and maintainability. The introduction of custom Hooks has even taken logic reuse to a new level, enabling developers to encapsulate and share any complex logic without being limited to React’s built-in functionality. Mastering the principles of Hooks and their application is crucial to modern front-end development, helping us build more efficient, clean and powerful React applications.