- vừa được xem lúc

Tạo logic tái sử dụng với Custom Hooks trong React

0 0 1

Người đăng: Gung Typical

Theo Viblo Asia

Các Hook tích hợp sẵn của React như useState và useEffect cho phép quản lý state và các tính năng lifecycle trực tiếp trong các functional component. Tuy nhiên, khi cần logic tái sử dụng trên nhiều component, custom Hooks cung cấp một giải pháp để giữ cho code gọn gàng và dễ mở rộng.

Khái niệm và lợi ích của React Hooks

React Hooks là gì? Các Hook tích hợp sẵn của React như useState và useEffect cho phép quản lý state và các tính năng lifecycle trực tiếp trong functional component. Nhưng khi chúng ta cần logic tái sử dụng trên nhiều component, custom Hooks cung cấp một cách để giữ cho code được tổ chức và dễ mở rộng.

Hook hữu ích như thế nào và khi nào nên sử dụng chúng? Hook đóng gói logic tái sử dụng, giúp dễ dàng quản lý state và các tính năng lifecycle trên nhiều component. Custom Hooks đặc biệt hữu ích để xử lý forms, lấy dữ liệu và chia sẻ state, giảm sự dư thừa và làm cho codebase có thể mở rộng và dễ bảo trì.

Điều gì tạo nên một hàm là 'Hook' trong React? Một hàm được coi là Hook trong React nếu nó đóng gói logic stateful có thể tái sử dụng và tuân theo quy ước đặt tên bằng cách thêm tiền tố "use". Tiền tố "use" báo hiệu cho React rằng đó là một Hook, cho phép nó áp dụng các quy tắc nội bộ đặc biệt (sẽ được đề cập sau) để quản lý hành vi của hàm.

Ví dụ về ứng dụng Custom Hooks trong quản lý Form

Ví dụ ứng dụng của chúng ta bao gồm các forms thu thập thông tin người dùng. Nó có hai phần: 'Thông tin cá nhân' và 'Thông tin thanh toán'. Mỗi phần thu thập dữ liệu và yêu cầu xác thực. Dưới đây là cách custom hooks đơn giản hóa việc xử lý và xác thực form.

Đây là cấu trúc của ứng dụng, chúng ta sẽ xem xét cụ thể các tệp này: PersonalDetailsForm.jsx để định nghĩa các trường form, useForm.js là custom Hook để quản lý state và gửi form, và useValidation.js là custom Hook cho logic xác thực tập trung. image.png

1. PersonalDetailsForm.jsx – Sử dụng useForm và lược đồ xác thực

Đây là tệp thành phần cho biểu mẫu 'Thông tin cá nhân'.

import { Input, Dropdown, Button } from "@/components";
import useForm from "@/hooks/useForm";
import { validations } from "@/util/validationHelper"; const PersonalDetailsForm = ({ title }) => { const initialData = { FirstName: "", LastName: "", Email: "", ReceiveMarketing: false }; // Validations const validationSchema = { FirstName: [ { validator: validations.required, message: "First name is required" }, { validator: (value) => validations.minLength(value, 2), message: "First name must be at least two characters" } ], LastName: [ { validator: validations.required, message: "Last name is required" } ], Email: [ { validator: validations.required, message: "Email is required" }, { validator: validations.email, message: "Invalid email" } ] }; // Custom Hook useForm for state management and validation handling const { formData, handleInputChange, handleSubmit, validationProps } = useForm(initialData, () => console.log(formData), validationSchema); return ( <> <div className="bg-white rounded-md p-6"> <form onSubmit={handleSubmit}> <h2 className="text-2xl font-semibold text-orange-600 pb-4"> {title} </h2> <Input label="First Name" placeholder="John" name="FirstName" onChange={handleInputChange} value={formData.FirstName} {...validationProps("FirstName")} /> <Input label="Last Name" placeholder="Doe" name="LastName" onChange={handleInputChange} value={formData.LastName} {...validationProps("LastName")} /> <Input label="Email" placeholder="Email" name="Email" onChange={handleInputChange} value={formData.Email} {...validationProps("Email")} /> <Dropdown label="Would you like to receive marketing emails from us?" name="ReceiveMarketing" onChange={handleInputChange} value={formData.ReceiveMarketing} items={[ { label: "Yes", value: true }, { label: "No", value: false } ]} isRequired={false} isValid={true} /> <Button type="submit" text="Submit" /> </form> </div> </> );
}; export default PersonalDetailsForm;

Trong PersonalDetailsForm.jsx, chúng ta khởi tạo initialData để định nghĩa giá trị trường và sử dụng validationSchema để chỉ định các quy tắc xác thực. Chúng được truyền cho custom Hook useForm, Hook này cung cấp các hàm như handleInputChange để cập nhật state form và validationProps để xử lý lỗi và hiển thị thông báo lỗi cho người dùng.

2. useForm.js Custom Hook – Xử lý trạng thái biểu mẫu và gửi

Custom Hook useForm quản lý state form với formData và xử lý việc gửi form. Các thay đổi trường form được xử lý bằng handleInputChange. Hàm này phân tích cú pháp các kiểu dữ liệu khác nhau (như text, checkbox và number) và xác thực từng trường khi thay đổi, giữ cho component PersonaDetailsForm của chúng ta gọn gàng.

import { useState } from "react";
import useValidation from "@/hooks/useValidation"; const useForm = (initialValues, onSubmitCallback, validationSchema = {}) => { // Set form data state const [formData, setFormData] = useState(initialValues); // Calling another custom Hook - useValidation const { validateFieldOnChange, validateAllFields, validationProps } = useValidation(formData, validationSchema); const handleInputChange = (e) => { const { name, type, value, checked } = e.target; const parsedValue = type === "checkbox" ? checked : value === "true" // Convert string representation of boolean to boolean ? true : value === "false" ? false : type === "number" ? value === "" ? "" : parseFloat(value) // Parse as float if it's a number, allow empty string (for when user clears input) : value; // e.target.value setFormData({ ...formData, [name]: parsedValue }); validateFieldOnChange(name, value); }; const resetForm = () => { const resetValues = Object.keys(formData).reduce((acc, key) => { acc[key] = ""; return acc; }, {}); setFormData(resetValues); }; const handleSubmit = async (e) => { e.preventDefault(); if (validateAllFields()) { try { await onSubmitCallback(formData); } catch (error) { console.error("Error during form submission", error); } } else { console.warn("Validation Failed"); alert("Invalid Form"); } }; return { formData, handleInputChange, resetForm, handleSubmit, validationProps };
}; export default useForm;

3. useValidation.js Custom Hook - Logic xác thực tập trung

Custom Hook useValidation tập trung logic xác thực, với các hàm như validateFieldOnChange để kiểm tra các trường trong thời gian thực và validateAllFields để xác nhận tất cả các trường đáp ứng các yêu cầu trước khi gửi.

Sử dụng validationProps, chúng ta có thể dễ dàng đính kèm phản hồi xác thực vào từng trường. Hãy xem các component input trong PersonalDetailsForm.jsx để xem cách các validation props được trải rộng.

import { useState, useMemo } from "react"; const useValidation = (formData, validationSchema) => { const [errors, setErrors] = useState({}); const memoValidationSchema = useMemo( () => validationSchema, [validationSchema] ); // Validate field on change const validateFieldOnChange = (name, value) => { if (memoValidationSchema[name]) { const fieldErrors = validateField(value, memoValidationSchema[name]); setErrors((prevErrors) => ({ ...prevErrors, [name]: fieldErrors })); } }; // Validate field against validation schema const validateField = (value, rules) => { let errors = []; for (const rule of rules) { if ( typeof rule === "object" && rule.validator && !rule.validator(value) ) { errors.push(rule.message); // Add error message if validation fails } } return errors; }; // Validate all fields against their validation schema const validateAllFields = () => { const newErrors = []; for (const field in memoValidationSchema) { let fieldErrors = validateField( formData[field], memoValidationSchema[field] ); if (fieldErrors.length > 0) { newErrors[field] = fieldErrors; } } setErrors(newErrors); return Object.keys(newErrors).length === 0; }; // Validation props to use in form field component for error handling const validationProps = useMemo( () => (name) => ({ isValid: !errors?.[name] || errors?.[name].length === 0, errorMessage: errors?.[name]?.[0] }), [errors] ); return { validateFieldOnChange, validateAllFields, validationProps };
}; export default useValidation;

4. PaymentDetailsForm.jsx – Khả năng tái sử dụng

Đây là tệp component cho form 'Thông tin thanh toán'. Thiết lập của chúng ta cho phép chúng ta tái sử dụng useForm và useValidation trong bất kỳ component form nào như PaymentDetailsForm.jsx mà không cần sao chép logic.

Còn nếu không thì sao? Nếu không có custom Hooks, mỗi form sẽ cần logic quản lý state và xác thực riêng, dẫn đến code lặp lại và lộn xộn. Custom Hooks tập trung chức năng này, cung cấp một phương pháp tái sử dụng tuân theo nguyên tắc DRY (Don't Repeat Yourself - Không lặp lại chính mình).

Quy tắc sử dụng Hooks và kết luận

Để đảm bảo rằng Hooks hoạt động đáng tin cậy, React thực thi một vài quy tắc chính để duy trì hành vi nhất quán trên các component.

  • Luôn gọi Hooks ở cấp cao nhất của hàm React của bạn: Không sử dụng Hooks bên trong vòng lặp, điều kiện, hàm lồng nhau hoặc sau khi trả về có điều kiện. Điều này đảm bảo rằng Hooks được gọi theo cùng một thứ tự trên mỗi lần render, điều mà React dựa vào để theo dõi state một cách chính xác.
  • Không gọi Hooks trong trình xử lý sự kiện hoặc class component: Hooks được thiết kế đặc biệt để sử dụng trong functional component hoặc trong custom Hooks, việc sử dụng chúng ở những nơi khác có thể dẫn đến hành vi không mong muốn.
  • Chỉ sử dụng Hooks trong các hàm React hoặc custom Hooks: Custom Hooks có thể gọi các Hooks khác, tuân theo các quy tắc tương tự, như trong ví dụ của chúng ta, nơi Hook useForm gọi Hook useValidation.

Tính tái sử dụng và khả năng bảo trì là cần thiết để xây dựng các ứng dụng có thể mở rộng. Custom Hooks trong React cho phép chúng ta đạt được điều này bằng cách đóng gói logic có thể được chia sẻ trên các component. Điều này dẫn đến code sạch hơn, theo module hơn, dễ hiểu, kiểm tra và mở rộng hơn.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tìm hiểu về Redux Thunk

Chào mọi người, nếu bạn là người đã biết về React và đang làm quen với Redux chắc hẳn bạn đang rất mơ hồ về các khái niệm cơ bản của Redux như dispatch, store, action creator,... bạn còn đang vật lộn với đống document của Redux để hiểu những khái niệm đó và bạn nghe ai đó trong team nói về Redux Thu

0 0 399

- vừa được xem lúc

[React] Giới thiệu tổng quát về Redux Toolkit

1. Redux Toolkit (RTK) là gì và tại sao lại có nó. . .

0 0 6.6k

- vừa được xem lúc

Uống Pepsi code Vue đi - Uống Cocacola code React nha ;)

. (Nguồn ảnh: Internet). Chào các bạn, chào các bạn. Let's go . 1.

0 0 147

- vừa được xem lúc

Cài đặt taillwind css cho dự án React

Trong bài viết cùng mình tìm hiểu cách cài đặt tailwind css cho một dự án React sẵn có. .

0 0 146

- vừa được xem lúc

Formik vs React Hook Form (Phần 1)

Các lập trình viên Front End đều làm việc rất nhiều với form cùng sự phức tạp của ứng dụng. Do vậy chúng ta cần những thư viện form mạnh mẽ hỗ trợ quản lý các form state, form validation... Thành phần module. Formik bao gồm có 9 dependencies khác. . React Hook Form thì không có.

0 0 372

- vừa được xem lúc

Hướng dẫn React Redux cho người mới bắt đầu - Phần 1

Lời mởi đầu. Chào các bạn, ở thời điểm thực hiện bài viết này mình cũng là một người đang bắt đầu tìm hiểu và học với ReactJs và Redux, trong quá trình tìm hiểu đọc các tài liệu về thư viện này mình có tìm được một bài hướng dẫn khá hay nên đã quyết định chia sẻ với mọi người .

0 0 281