次の方法で共有


モジュール間で状態を共有

この記事では、Dynamics 365 Commerce のデータ アクションを使用して複数のモジュール間で状態を共有する方法について説明します。

データ アクションは、同じページ上の複数のモジュール間で状態を共有する必要がある場合に、状態管理の重要な役割を果たします。 一般に、実行中の Node アプリケーションのアプリケーション状態内で、状態が共有されます。

この例では、2 つのモジュールが基本的な相互作用を共有します。 一方のモジュール (sample-button) にはボタンがあり、もう一方のモジュール (sample-message) にはボタンが選択されている場合にメッセージが表示されます。

最初に、ボタンが選択された回数を含むオブジェクトを返すデータ アクションが必要です。 以下にコードの例を示します。

// sample-state.ts
import { CacheType, createObservableDataAction, IAction, IActionContext, IActionInput, IAny, ICreateActionContext, IGeneric } from '@msdyn365-commerce/core';
export interface ISampleState {
    clickCount: number;
}

/**
 * SampleState - action input
 */
export class SampleStateInput implements IActionInput {
    public getCacheKey = () => `SampleState`;
    public getCacheObjectType = () => 'SampleState';
    public dataCacheType = (): CacheType => 'request';
}

/**
 * SampleState - action
 */
export async function sampleStateAction(input: SampleStateInput, ctx: IActionContext): Promise<ISampleState> {
    return { clickCount: 0 };
}

/**
 * SampleState - create new input for create action
 */
const createInput = (inputData: ICreateActionContext<IGeneric<IAny>>): IActionInput => {
    return new SampleStateInput();
};

/**
 * SampleState - create action
 */
export default createObservableDataAction<ISampleState>({
    action: <IAction<ISampleState>>sampleStateAction,
    input: createInput
});

現在の状態では、このデータ アクションには実装はありません。 キャッシュにオブジェクトを格納する場所を作成するだけです。 この例の 2 つのモジュールは相互に通信する必要があるため、両方でこのオブジェクトを遵守すると便利です。 モジュールにこのオブジェクトへの許可を付与するには、これらのモジュールでは、ページ読み込みデータ アクションとして前に作成したデータ アクションを登録する必要があります。

sample-button モジュールのコードを次に示します。

// sample-button.definition.json
{
    "$type": "contentModule",
    "friendlyName": "Sample Button",
    "name": "sample-button",
    "description": "Sample Button",
    "categories": ["sample-button"],
    "tags": ["samples"],
    "module": {
        "view": "./sample-button",
        "dataActions": {
            "sampleState": {
                "path": "../../actions/sample-state/sample-state"
            }
        }
    }
}

sample-message モジュールのコードを次に示します。

// sample-message.definition.json
{
    "$type": "contentModule",
    "friendlyName": "Sample Message",
    "name": "sample-message",
    "description": "Sample Message",
    "categories": ["sample-message"],
    "tags": ["samples"],
    "dataActions": {
        "sampleState": {
            "path": "../../actions/sample-state/sample-state"
        }
    }
}

これで、両方のモジュールがデータ アクションに登録されます。 したがって、これらはどちらもアプリケーション状態で同じオブジェクトを遵守します。 次の手順は、sample-button モジュールにイベントをクリックするユーザーがいる場合、アプリケーション状態を更新することです。 その後、アプリケーション状態を遵守するモジュールはすべて自動的に更新される必要があります。 sample-message モジュールのコードを次に示します。

// sample-message.data.ts
import { AsyncResult } from '@msdyn365-commerce/retail-proxy';
import { ISampleState } from '../../actions/sample-state/sample-state';
export interface ISampleMessageData {
    sampleState: AsyncResult<ISampleState>;
}
// sample-message.tsx
import * as React from 'react';
import { ISampleMessageData } from './sample-message.data';
import { ISampleMessageProps } from './sample-message.props.autogenerated';

/**
 * SampleMessage Module used for showcasing cross-module communication
 * @extends {React.Component<ISampleMessageProps<ISampleMessageData>>}
 */
export default class SampleMessage extends React.Component<ISampleMessageProps<ISampleMessageData>> {
    constructor(props: ISampleMessageProps<ISampleMessageData>) {
        super(props);
    }
    public render(): JSX.Element {
        if(this.props.data.sampleState.result) {
            return (<h3>The Button has been clicked {this.props.data.sampleState.result.clickCount} times.</h3>);
        }
        return (<h3>Error: No Sample State Detected</h3>);
    }
}

sample-message モジュールは非常に簡単です。 ページ読み込みデータ アクションを使用して ISampleState 値を要求しています。 次に、返されるデータに基づいて、単純なメッセージが表示されます。 アプリケーション状態は MobX によって内部で動作するため、このモジュールは変更を遵守しているデータが変化すると自動的に反応できます。

最後に、ユーザー クリック イベントに応じてアプリケーション状態を更新する sample-button モジュールのコードを次に示します。

// sample-button.data.ts
import { AsyncResult } from '@msdyn365-commerce/retail-proxy';
import { ISampleState } from '../../actions/sample-state/sample-state';
export interface ISampleButtonData {
    sampleState: AsyncResult<ISampleState>;
}
// sample-button.tsx
import * as React from 'react';
import { ISampleButtonData } from './sample-button.data';
import { ISampleButtonProps } from './sample-button.props.autogenerated';
import { SampleStateInput } from '../../actions/sample-state/sample-state';

/**
 * SampleButton component used for showcasing cross-module communication
 * @extends {React.Component<ISampleButtonProps<ISampleButtonData>>}
 */
export default class SampleButton extends React.Component<ISampleButtonProps<ISampleButtonData>> {
    constructor(props: ISampleButtonProps<ISampleButtonData>) {
        super(props);
        this._onClick.bind(this);
    }
    public render(): JSX.Element {
        return (
            <button onClick={this._onClick}>
                Click Me!
            </button>
        );
    }

    // OnClick Handler should update application state
    private _onClick = (e: React.MouseEvent): void => {
        if (this.props.data.sampleState.result) {
            // This will directly update our application state, which should trigger all modules observing the state to update
            this.props.context.actionContext.update(new SampleStateInput(), { clickCount: this.props.data.sampleState.result.clickCount + 1 });
        }
    }
}

ご覧のように、onClick ハンドラーが actionContext.update() を呼び出します。 このメソッドを使用すると、アプリケーション状態を直接変更できます。 状態が変更された場合、MobX は sample-message モジュールを含む状態が遵守できるすべてのモジュールを引き継ぎ、再表示します。

追加リソース

チェーン データ アクション

バッチ データ アクション

監視可能なデータ アクションの作成

データ アクション キャッシュの設定

データ アクションの上書き

データ アクションのフック