序章

複雑なWebプロジェクトでは、多くの場合、サードパーティのウィジェットを使用する必要があります。 しかし、フレームワークを使用していて、ウィジェットが純粋なJavaScriptでのみ利用可能である場合はどうでしょうか。

プロジェクトでJavaScriptウィジェットを使用するには、フレームワーク固有のラッパーを作成するのが最善の方法です。

ag-Grid は、データグリッドに情報を表示するためのJavaScriptウィジェットです。 これにより、情報を動的に並べ替え、フィルタリング、および選択できます。 ag-Grid Reactラッパーも提供します。 ag-grid-react.

この記事では、 ag-grid-communityag-grid-react サードパーティのウィジェットをReactコンポーネントにラップする方法を学ぶための基礎として。 ReactPropsとウィジェットの構成オプションの間のマッピングを設定します。 また、Reactコンポーネントを介してウィジェットのAPIを公開します。

前提条件

この記事をフォローするには、次のものが必要です。

  • Reactにある程度精通している。 React.jsシリーズのコーディング方法をご覧ください。

ステップ1—JavaScriptウィジェットを理解する

一般に、ほとんどのJavaScriptウィジェットには次のものがあります。

  • 構成オプション
  • パブリックAPI
  • 放送されたイベント

それはまさにあなたが対話する方法です ag-Grid. グリッドのプロパティ、イベント、コールバック、およびAPI の適切な説明は、公式ドキュメントにあります。

つまり、データグリッドは次のことを定義します。

  • グリッドプロパティは、行アニメーションなどのグリッドの機能を有効にします。
  • グリッドAPIは、実行時にグリッドと対話します(たとえば、選択したすべての行を取得します)
  • グリッドイベント行の並べ替えや行の選択など、グリッドで特定のイベントが発生したときにグリッドから発行されます
  • グリッドコールバックは、必要なときにアプリケーションからグリッドに情報を提供するために使用されます(たとえば、メニューが表示されるたびにコールバックが呼び出され、アプリケーションがメニューをカスタマイズできるようになります)

グリッドオプションの使用法を示す非常に基本的な純粋なJavaScript構成を次に示します。

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; }
}

まず、JavaScriptデータグリッドは次のように初期化されます。

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

それで、 ag-Grid APIメソッドを使用してオブジェクトをにアタッチします gridOptions JavaScriptデータグリッドを制御するために使用できます。

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

ただし、 ag-Grid Reactコンポーネントとして使用されるため、データグリッドを直接インスタンス化することはありません。 それがラッパーコンポーネントの仕事です。 のインスタンスとのすべての相互作用 ag-Grid コンポーネントインスタンスを介して発生します。

たとえば、グリッドによってアタッチされたAPIオブジェクトに直接アクセスすることはできません。 コンポーネントのインスタンスを介してアクセスします。

ステップ2—ラッパーコンポーネントが何をすべきかを決定する

構成オプションとコールバックをグリッドに直接渡すことはありません。 Reactラッパーコンポーネントは、ReactPropsを介してオプションとコールバックを受け取ります。

バニラJavaScriptグリッドで使用できるすべてのグリッドオプションは、 Reactdatagridでも使用できる必要があります。 また、インスタンスのイベントを直接リッスンしません ag-Grid. 使用している場合 ag-Grid Reactコンポーネントとして、 ag-Grid Reactコンポーネントの小道具から利用できるはずです。

これはすべて、React固有のデータグリッドラッパーが周りにあることを意味します ag-Grid したほうがいい:

  • 入力バインディング間のマッピングを実装します( rowData) と ag-Gridの構成オプション
  • によって発行されたイベントをリッスンする必要があります ag-Grid それらをコンポーネント出力として定義します
  • コンポーネントの入力バインディングの変更をリッスンし、グリッドの構成オプションを更新します
  • によって添付されたAPIを公開する ag-GridgridOptions そのプロパティを介して

次の例は、ReactPropsを使用してテンプレートでReactデータグリッドを構成する方法を示しています。

<AgGridReact
    // useful for accessing the component directly via ref - optional
    ref="agGrid"

    // 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}

    // these are registering event callbacks
    onCellClicked={this.onCellClicked}
    onColumnResized={this.onColumnEvent}

    // inside onGridReady, you receive the grid APIs if you want them
    onGridReady={this.onGridReady}
/>

要件を理解したので、次の場所でどのように実装したかを見てみましょう。 ag-Grid.

ステップ3—ReactWrapperを実装する

まず、テンプレートでReactデータグリッドを表すReactコンポーネントAgGridReactを定義する必要があります。 このコンポーネントはレンダリングします DIV データグリッドのコンテナとして機能する要素。 ネイティブを手に入れるには DIV Refs機能を使用する要素:

export class AgGridReact extends React.Component {
    protected eGridDiv: HTMLElement;

    render() {
        return React.createElement("div", {
            style: ...,
            ref: e => {
                this.eGridDiv = e;
            }
        }, ...);
    }
}

インスタンス化する前に ag-Grid、すべてのオプションも収集する必要があります。 全て ag-Grid プロパティとイベントは、ReactPropsとして提供されます。 AgGridReact 成分。 The gridOptions プロパティは、すべてのデータグリッドオプションを格納するために使用されます。 利用可能になり次第、Reactプロップからすべての構成オプションをコピーする必要があります。

そのために、copyAttributesToGridOptions関数を実装しました。 これは、あるオブジェクトから別のオブジェクトにプロパティをコピーするユーティリティ関数です。

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;
    }
}

オプションはにコピーされます componentDidMount すべての小道具が更新された後のライフサイクルメソッド。 これは、グリッドをインスタンス化するフックでもあります。 インスタンス化されるときにネイティブDOM要素をデータグリッドに渡す必要があるため、 DIV refs機能を使用してキャプチャされた要素:

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;
    }
}

上記のように、列として渡された子が存在するかどうかも確認し、列定義として構成オプションに追加します。

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

ステップ4—グリッドプロパティの更新を同期する

グリッドが初期化されたら、データグリッドの構成オプションを更新するためにReactPropsへの変更を追跡する必要があります。 ag-Grid それを行うためのAPIを実装します。 たとえば、 headerHeight プロパティの変更があります setHeaderHeight ヘッダーの高さを更新するメソッド。

Reactの用途 componentWillReceiveProps 変更についてコンポーネントに通知するライフサイクルメソッド。 ここに更新ロジックを配置します。

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);
    }
}

基本的に、私たちはのリストを調べます ag-Gridの構成プロパティとコールバックを確認し、それらのいずれかが変更されているかどうかを確認します。 すべての変更を changes 配列し、を使用してそれらを処理します processOnChange 方法。

この方法は2つのことを行います。 まず、React Propsの変更を確認し、 gridOptions 物体。 次に、APIメソッドを呼び出して、変更についてグリッドに通知します。

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);
        }

        ...
    }
}

ステップ5—APIを公開する

実行時のReactグリッドとの対話は、グリッドAPIを介して行われます。 列のサイズを調整したり、新しいデータソースを設定したり、選択したすべての行のリストを取得したりすることができます。 JavaScriptデータグリッドが開始されると、 api グリッドオプションオブジェクトへのオブジェクト。 このオブジェクトを公開するには、コンポーネントインスタンスに割り当てます。

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;
    }
}

以上です。

結論

このチュートリアルでは、バニラJavaScriptライブラリをReactフレームワーク内で機能するように適合させる方法を学びました。

このトピックの詳細については、「他のライブラリとの統合」に関する公式のReactドキュメントを参照してください。