Thứ năm, 12/12/2019 | 00:00 GMT+7

Cách gói một gói JavaScript Vanilla để sử dụng trong React

Các dự án web phức tạp thường yêu cầu sử dụng các widget của bên thứ ba. Nhưng điều gì sẽ xảy ra nếu bạn đang sử dụng một khuôn khổ và tiện ích chỉ có sẵn trong JavaScript thuần túy?

Để sử dụng trình JavaScript trong dự án của bạn, cách tốt nhất sẽ là tạo một shell bọc dành riêng cho khung công tác. Đó là những gì hướng dẫn này là về.

Trong bài viết này, ta sẽ hướng dẫn bạn cách gói một widget của bên thứ 3 vào một thành phần React bằng cách sử dụng ag-Grid làm ví dụ. Ta sẽ chỉ cho bạn cách ta cài đặt ánh xạ giữa React Props và các tùy chọn cấu hình của tiện ích con. Bạn cũng sẽ học cách hiển thị API của tiện ích con thông qua thành phần React.

Bước 1 - Hiểu tiện ích JS

Hầu hết các widget có thể được cấu hình thông qua các tùy chọn cấu hình. Thông thường họ cũng xác định API công khai và các sự kiện phát sóng.

Nói chung, hầu hết các widget đều có:

  • Tùy chọn cấu hình
  • API công khai
  • Các sự kiện được phát sóng

Đó chính xác là cách bạn tương tác với ag-Grid. Bạn có thể tìm thấy mô tả tốt cho các thuộc tính, sự kiện, lệnh gọi lại và API của lưới trong tài liệu chính thức . Nói tóm lại, datagrid định nghĩa:

  • Thuộc tính lưới cho phép các tính năng của lưới, như hoạt ảnh hàng.
  • API lưới để tương tác với lưới trong thời gian chạy, ví dụ: để lấy tất cả các hàng đã chọn
  • Lưới Sự kiện do lưới phát ra khi một số sự kiện nhất định xảy ra trong lưới, như sắp xếp hàng hoặc chọn hàng
  • Grid Callbacks được sử dụng để cung cấp thông tin từ ứng dụng của bạn vào lưới khi ứng dụng cần, ví dụ: một lệnh gọi lại được gọi mỗi khi một menu được hiển thị cho phép ứng dụng của bạn tùy chỉnh menu.

Đây là cấu hình JavaScript thuần túy rất cơ bản thể hiện việc sử dụng các tùy chọn lưới:

let gridOptions = {      // PROPERTIES - object properties, myRowData and myColDefs are created somewhere in your application     rowData: myRowData,     columnDefs: myColDefs,      // PROPERTIES - simple boolean / string / number properties     pagination: true,     rowSelection: 'single',      // EVENTS - add event callback handlers     onRowClicked: function(event) { console.log('a row was clicked'); },     onColumnResized: function(event) { console.log('a column was resized'); },     onGridReady: function(event) { console.log('the grid is now ready'); },      // CALLBACKS     isScrollLag: function() { return false; } } 

Khi lưới dữ liệu JavaScript được khởi tạo như thế này:

new Grid(this._nativeElement, this.gridOptions, ...); 

ag-Grid gắn đối tượng với các phương thức API vào lưới Các gridOptions được dùng để kiểm soát lưới dữ liệu JavaScript:

// get the grid to refresh gridOptions.api.refreshView(); 

Tuy nhiên, khi ag-Grid được sử dụng như một thành phần React, ta không khởi tạo trực tiếp datagrid. Đó là công việc của thành phần wrapper.

Tất cả các tương tác với cá thể của ag-Grid xảy ra thông qua cá thể thành phần. Ví dụ: ta không có quyền truy cập trực tiếp vào đối tượng API được đính kèm bởi lưới. Ta sẽ truy cập nó thông qua cá thể của thành phần.

Bước 2 - Xác định những gì một thành phần Wrapper nên làm

Ta không bao giờ chuyển trực tiếp các tùy chọn cấu hình và lệnh gọi lại vào lưới.

Một thành phần shell bọc React nhận các tùy chọn và gọi lại thông qua React Props.

Tất cả các tùy chọn lưới có sẵn cho lưới JavaScript vani cũng phải có sẵn trong React datagrid . Ta cũng không trực tiếp lắng nghe các sự kiện trên ví dụ của ag-Grid. Nếu ta đang sử dụng ag-Grid làm thành phần React, thì tất cả các sự kiện do ag-Grid phát ra sẽ có sẵn thông qua các đạo cụ của thành phần React.

Tất cả điều này nghĩa là một shell bọc datagrid cụ thể của React xung quanh ag-Grid phải:

  • triển khai ánh xạ giữa các ràng buộc đầu vào (như rowData) và các tùy chọn cấu hình của ag-Grid
  • nên lắng nghe các sự kiện do ag-Grid phát ra và xác định chúng dưới dạng kết quả thành phần
  • lắng nghe những thay đổi trong ràng buộc đầu vào của thành phần và cập nhật các tùy chọn cấu hình trong lưới
  • hiển thị API được ag-Grid đính kèm vào lưới

Ví dụ sau minh họa cách React datagrid được cấu hình trong một mẫu sử dụng React Props:

<AgGridReact      // useful for accessing the component directly via ref     ref="agGrid"      // these are simple attributes, not bound to any state or prop     rowSelection="multiple"      // these are bound props, so can use anything in React state or props     columnDefs={this.props.columnDefs}     showToolPanel={this.state.showToolPanel}      // this is a callback     isScrollLag={this.myIsScrollLagFunction.bind(this)}      // these are registering event callbacks     onCellClicked={this.onCellClicked.bind(this)}"     onColumnResized={this.onColumnEvent.bind(this)}"     onGridReady={this.onGridReady.bind(this)}" // inside onGridReady, you receive the grid APIs if you want them /> 

Bây giờ ta đã hiểu yêu cầu, hãy xem cách ta triển khai nó tại ag-Grid .

Bước 3 - Triển khai React Wrapper

Đầu tiên, ta cần xác định một thành phần React AgGridReact đại diện cho lưới dữ liệu React của ta trong các mẫu. Thành phần này sẽ hiển thị một phần tử DIV sẽ đóng role là containers cho datagrid. Để nắm giữ phần tử DIV root , ta sử dụng chức năng Refs :

export class AgGridReact extends React.Component {     protected eGridDiv: HTMLElement;      render() {         return React.createElement("div", {             style: ...,             ref: e => {                 this.eGridDiv = e;             }         }, ...);     } } 

Trước khi có thể khởi tạo ag-Grid, ta cũng cần thu thập tất cả các tùy chọn. Tất cả các thuộc tính và sự kiện của ag-Grid đều có dạng React Props trên thành phần AgGridReact . gridOptions tính gridOptions được sử dụng để lưu trữ tất cả các tùy chọn gridOptions . Ta cần sao chép tất cả các tùy chọn cấu hình từ các đạo cụ React ngay khi chúng có sẵn.

Để làm điều đó, ta đã triển khai hàm copyAttributesToGridOptions . Đó là một chức năng tiện ích sao chép các thuộc tính từ đối tượng này sang đối tượng khác. Đây là ý chính của hàm:

export class ComponentUtil {     ...     public static copyAttributesToGridOptions(gridOptions, component, ...) {         ...         // copy all grid properties to gridOptions object         ComponentUtil.ARRAY_PROPERTIES             .concat(ComponentUtil.STRING_PROPERTIES)             .concat(ComponentUtil.OBJECT_PROPERTIES)             .concat(ComponentUtil.FUNCTION_PROPERTIES)             .forEach(key => {                 if (typeof component[key] !== 'undefined') {                     gridOptions[key] = component[key];                 }             });           ...           return gridOptions;     } } 

Các tùy chọn được sao chép trong phương thức vòng đời componentDidMount sau khi tất cả các đạo cụ đã được cập nhật. Đây cũng là móc để ta khởi tạo lưới. Ta cần chuyển một phần tử DOM root vào lưới dữ liệu khi nó được khởi tạo, vì vậy ta sẽ sử dụng phần tử DIV được chụp bằng chức năng refs. Đây là cách tất cả trông:

export class AgGridReact extends React.Component {     gridOptions: AgGrid.GridOptions;      componentDidMount() {         ...          let gridOptions = this.props.gridOptions || {};         if (AgGridColumn.hasChildColumns(this.props)) {             gridOptions.columnDefs = AgGridColumn.mapChildColumnDefs(this.props);         }          this.gridOptions = AgGrid.ComponentUtil.copyAttributesToGridOptions(gridOptions, this.props);          new AgGrid.Grid(this.eGridDiv, this.gridOptions, gridParams);          this.api = this.gridOptions.api;         this.columnApi = this.gridOptions.columnApi;     } } 

Bạn có thể thấy ở trên rằng ta cũng kiểm tra xem có con nào được chuyển dưới dạng cột hay không và thêm sau đó vào các tùy chọn cấu hình dưới dạng định nghĩa cột:

if (AgGridColumn.hasChildColumns(this.props)) {     gridOptions.columnDefs = AgGridColumn.mapChildColumnDefs(this.props); } 

Bước 4 - Đồng bộ hóa các cập nhật thuộc tính lưới

Khi lưới được khởi tạo, ta cần theo dõi các thay đổi đối với React Props để cập nhật các tùy chọn cấu hình của lưới dữ liệu. ag-Grid triển khai một API để làm điều đó, ví dụ: nếu thuộc tính headerHeight thay đổi thì có phương thức setHeaderHeight để cập nhật chiều cao của tiêu đề.

React sử dụng phương thức vòng đời componentWillReceiveProps để thông báo cho một thành phần về các thay đổi. Đây là nơi ta đặt logic cập nhật của bạn :

export class AgGridReact extends React.Component {     componentWillReceiveProps(nextProps: any) {         const changes = <any>{};         const changedKeys = Object.keys(nextProps);          changedKeys.forEach((propKey) => {             ...             if (!this.areEquivalent(this.props[propKey], nextProps[propKey])) {                 changes[propKey] = {                     previousValue: this.props[propKey],                     currentValue: nextProps[propKey]                 };             }         });         AgGrid.ComponentUtil.getEventCallbacks().forEach((funcName: string) => {             if (this.props[funcName] !== nextProps[funcName]) {                 changes[funcName] = {                     previousValue: this.props[funcName],                     currentValue: nextProps[funcName]                 };             }         });           AgGrid.ComponentUtil.processOnChange(changes, this.gridOptions, this.api, this.columnApi);     } } 

Về cơ bản, ta xem qua danh sách các thuộc tính cấu hình và lệnh gọi lại của ag-Grid và kiểm tra xem có bất kỳ thuộc tính nào đã thay đổi hay không. Ta đặt tất cả các thay đổi trong mảng changes và sau đó xử lý chúng bằng phương thức processOnChange .

Phương pháp này thực hiện hai điều. Đầu tiên, nó xem xét các thay đổi trong React Props và cập nhật các thuộc tính trên đối tượng gridOptions . Tiếp theo, nó gọi các phương thức API để thông báo cho lưới về những thay đổi:

export class ComponentUtil {     public static processOnChange(changes, gridOptions, api, ...) {         ...         // reflect the changes in the gridOptions object         ComponentUtil.ARRAY_PROPERTIES             .concat(ComponentUtil.OBJECT_PROPERTIES)             .concat(ComponentUtil.STRING_PROPERTIES)             .forEach(key => {                 if (changes[key]) {                     gridOptions[key] = changes[key].currentValue;                 }             });          ...          // notify Grid about the changes in header height         if (changes.headerHeight) {             api.setHeaderHeight(changes.headerHeight.currentValue);         }          // notify Grid about the changes in page size         if (changes.paginationPageSize) {             api.paginationSetPageSize(changes.paginationPageSize.currentValue);         }          ...     } } 

Bước 5 - Hiển thị API

Tương tác với lưới React tại thời điểm chạy được thực hiện thông qua API lưới. Bạn có thể cần điều chỉnh kích thước cột, đặt nguồn dữ liệu mới, lấy danh sách tất cả các hàng đã chọn, v.v. Khi chạy datagrid JavaScript, nó sẽ gắn đối tượng api đối tượng tùy chọn lưới. Để hiển thị đối tượng này, ta gán nó cho cá thể thành phần:

export class AgGridReact extends React.Component {     componentDidMount() {         ...         new AgGrid.Grid(this.eGridDiv, this.gridOptions, gridParams);          this.api = this.gridOptions.api;         this.columnApi = this.gridOptions.columnApi;     } } 

Và đó là nó.

Kết luận

Trong hướng dẫn này, ta đã học cách điều chỉnh thư viện JavaScript vani để hoạt động trong khuôn khổ React. Để biết thêm thông tin về chủ đề này, bạn có thể tham khảo tài liệu React chính thức về Tích hợp với các thư viện khác


Tags:

Các tin liên quan

Cách phát triển một trình tải lên tệp tương tác với JavaScript và Canvas
2019-12-12
Cách sử dụng map (), filter () và Reduce () trong JavaScript
2019-12-12
Giải thích về lập trình chức năng JavaScript: Ứng dụng một phần và làm xoăn
2019-12-12
Giới thiệu về Closures và Currying trong JavaScript
2019-12-12
Bắt đầu với các hàm mũi tên ES6 trong JavaScript
2019-12-12
Cách đếm số nguyên âm trong một chuỗi văn bản bằng thuật toán JavaScript
2019-12-12
Cách sử dụng phép gán cấu trúc hủy trong JavaScript
2019-12-12
Giải thích về lập trình chức năng JavaScript: Kết hợp & truyền tải
2019-12-12
Cách sử dụng .every () và .some () để điều khiển mảng JavaScript
2019-12-12
Chuyển đổi Mảng sang Chuỗi trong JavaScript
2019-12-05