Cách cấu hình FormProvider và React Hook Form trong dự án có nhiều thành phần ở vị trí khác nhau

Ví dụ về lỗi sử dụng React Hook Form với Controller không nhận được FormProvider

Trong quá trình phát triển ứng dụng, một lỗi phổ biến xảy ra khi dùng React Hook Form với Controller mà không nhận được FormProvider từ bên ngoài, đặc biệt khi hai thành phần nằm ở các vị trí khác nhau trong dự án.

Tình huống cụ thể

Cấu trúc dự án:

  • apps/route: Chứa file sử dụng React Hook Form.
  • libs/ui: Chứa các thành phần giao diện, bao gồm thư mục form control với thành phần CustomInput sử dụng Controller.

Quy trình triển khai:

  1. Trong thư mục libs/ui, chúng ta tạo thành phần CustomInput và build thành một package với tên là @myproject/ui.
  2. Trong apps/route, cài đặt package @myproject/ui từ libs/ui thông qua file package.json.
  3. Trong apps/route, tạo file uploadfile để sử dụng biểu mẫu từ React Hook Form. Tại đây, chúng ta sử dụng useForm và truyền FormProvider xuống các thành phần con, bao gồm CustomInput.

Lỗi gặp phải

Khi chạy ứng dụng, thành phần CustomInput không nhận được formContext từ FormProvider. Kết quả là React Hook Form báo lỗi:

Error: control = null

Nguyên nhân lỗi

Nguyên nhân chính nằm ở cách quản lý React và các package liên quan trong hệ thống node_modules:

  • React trong @myproject/uiapps/route không đồng bộ, dẫn đến việc tạo hai phiên bản React độc lập trong dự án.
  • Hai phiên bản này gây ra lỗi khi truyền context từ FormProvider xuống CustomInput.

Giải pháp: Cấu hình Webpack để dùng chung package React

Để giải quyết vấn đề, chúng ta cần cấu hình Webpack trong file razzle.config.js của apps/route để đảm bảo sử dụng chung các package như ReactReact-DOM.

Cấu hình razzle.config.js

const path = require('path');

const root = path.resolve(__dirname, '.', 'node_modules');

module.exports = {
  modifyWebpackConfig({ webpackConfig }) {
    webpackConfig.resolve.alias = {
      ...webpackConfig.resolve.alias,
      react: path.resolve(root, 'react'), // Chỉ định đường dẫn tới React trong node_modules chung
      'react-dom': path.resolve(root, 'react-dom'), // Chỉ định đường dẫn tới React-DOM
    };
    return webpackConfig;
  },
};

Giải thích cấu hình

  • path.resolve(root, 'react'): Đảm bảo cả apps/routelibs/ui đều sử dụng cùng một phiên bản React từ thư mục node_modules gốc.
  • Tương tự, path.resolve(root, 'react-dom') giúp đồng bộ React-DOM.

Lợi ích

  • Đảm bảo các context, như formContext, được truyền chính xác giữa các thành phần.
  • Tránh việc tải nhiều phiên bản React, giúp giảm kích thước gói build và tăng hiệu suất.

Kết luận

Việc cấu hình Webpack để sử dụng chung package là giải pháp quan trọng trong các dự án monorepo hoặc khi sử dụng pnpm. Điều này không chỉ giải quyết lỗi React Hook Form mà còn cải thiện hiệu năng tổng thể của ứng dụng.

Xem thêm: Thêm Pipeline tùy chỉnh vào trong ICalculateCartPipeline.

Bình luận Facebook