SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

現場で役立つ! React向けライブラリ詳説

ステートマシンを実装するためのJavaScriptライブラリ「XState」の基本的なAPIを解説

現場で役立つ! React向けライブラリ詳説 第11回

  • X ポスト
  • このエントリーをはてなブックマークに追加

XStateのAPI

 次に、XStateの主要なAPIを紹介し、それぞれのAPIがどのように使用されるかを解説します。

ステートマシンを定義する - createMechine

 XStateの createMachine は、ステートマシンを定義するための関数です。この関数を使って、ステートマシンの初期状態、状態遷移、イベント、アクションなどを定義します(リスト1)。

[リスト1]createMachineの使用例(src/vending.machine.js)
import { createMachine } from 'xstate';

const vendingMachine = createMachine({
  id: 'vendingMachine', // (1)
  initial: 'idle', // (2)
  states: {
    // (3) ステートと遷移を定義する
  },
});

 (1)の id はステートマシンの識別子です。複数のステートマシンを扱う場合に、特定のステートマシンを扱うために利用します。ステートマシンを1つしか扱わない場合には省略しても構いませんが、名前がついていたほうがどんなステートマシンなのか意識しやすいので、筆者は常に記述しています。今回は自動販売機のステートマシンを作るので、vendingMachineと命名しました。

 (2) initial は最初の状態(初期ステート)を表すプロパティです。後述の states に定義した状態のうち、初期状態としてどの状態を使うか宣言します。

 (3)の states は各状態の定義です。どんな状態があるのか、何をすると状態が遷移するのか、状態が遷移する前後に何が起こるのか、などを定義することができます。

静的なステートマシンを動的に実行する - interpret

 XStateの interpret は、ステートマシンを実行するための関数です。createMachine で定義されたステートマシンを interpret に渡すことで、ステートマシンを実際に動かすことができます(リスト2)。

[リスト2]interpretの使用例(my-script.js)
import { createMachine, interpret } from 'xstate';

// ステートマシンの定義
const vendingMachine = createMachine({ /* ... */ });

// ステートマシンの実行
const service = interpret(vendingMachine);
service.start(); // (1)

 (1)の service.start() を実行することで、ステートマシンが実行中になります。createMachine ではステートマシンの静的な定義のみで、そのままでは動作しません。interpret でステートマシンを読み込んだサービスを作ることで、動的に処理を行わせることができます。

Reactのライフサイクルの管理下でステートマシンを実行する - useMachine

 次に、useMachine について解説します。これはXStateのコア機能というわけではありませんが、Reactから利用するためには必須の機能となるため、本連載の性質上、ここで解説します。

 useMachine は、Reactアプリケーションでステートマシンを簡単に統合するためのカスタムフックです。useMachine を使うことで、ステートマシンの現在のステートやイベントの送信などが容易になります(リスト3)。

[リスト3]useMachineの使用例(src/App.jsx)
import { useMachine } from '@xstate/react';
import { vendingMachine } from './vendingMachine';

// コンポーネントの定義
function VendingMachine() {
  const [state, send] = useMachine(vendingMachine); // (1)

  // ステートに応じた表示やイベントの送信を行う
}

 (1)にステートマシンを読み込ませることで、useMachine はステートマシンに基づいた状態管理を行います。戻り値の state は現在の状態を表すオブジェクトで、send はイベントを発生させるためのメソッドです。Reactコンポーネントから見ると、ボタンクリックなどの操作を起点にして send でイベントを発生させて、その結果として変化した state をUIに反映させる、といった使い方になります。

 sendsend('INSERT_COIN', item) のような形で、第一引数に発生させたいイベントの名前を、第二引数にイベントのパラメータを指定できます。

 これらのAPIを組み合わせることで、XStateを使ってアプリケーションの状態管理を効果的に行うことができます。

ステートマシンの定義

 続いて、XStateを使用してステートマシンを定義する方法について解説します。ステートマシンの定義には、初期ステート、状態遷移、イベント、ガード条件などの要素が含まれます。それぞれどのような情報を定義するのか、見ていきましょう。

初期ステート

 リスト1でも言及しましたが、ステートマシンが開始されたときの状態を初期ステートと呼びます。createMachine 関数内で initia プロパティを使用して初期ステートを設定します。

[リスト4]初期ステート(src/vending.machine.js)
const vendingMachine = createMachine({
  id: 'vendingMachine',
  initial: 'idle', // (1)
  states: {
    // 状態を定義する
  },
});

状態遷移

 状態遷移は、あるステートから別のステートへ移動することを指します。状態遷移は、createMachine 関数内の states プロパティで定義された各ステートに on プロパティを追加することで設定します。on プロパティは、イベント名をキーとし、遷移先のステート名を値とするオブジェクトです(リスト5)。

[リスト5]状態遷移を定義する(src/vending.machine.js)
const vendingMachine = createMachine({
  id: 'vendingMachine',
  initial: 'idle',
  states: {
    idle: {
      description: "初期状態", // (2)
      on: {
        // 「INSERT_COIN」イベントで「inserting」ステートへ遷移
        INSERT_COIN: 'inserting', // (1)
      },
    },
    inserting: {
      description: "お金を投入中",
      on: {
        // 「INSERT_COIN」イベントで「inserting」ステート(自身)へ遷移
        INSERT_COIN: "inserting",
        // 「HAS_ENOUGH_AMOUNT」イベントで「ready」ステートへ遷移
        HAS_ENOUGH_AMOUNT: "ready",
      },
    },
    // その他のステートを定義
  },
});

 (1)のように定義することで、イベントと遷移先を表現できます。イベント名は、通常大文字とアンダースコアを使用して表記します(例: INSERT_COIN )。

 また、ステートには(2)のように description を記載することもできます。読みやすさのために、どのような状態なのかを記載しておくとよいでしょう。

 ちなみに、onプロパティは「イベント名: オブジェクト」の形でも定義できます。この場合は、リスト6のように記述します。

[リスト6]イベントをオブジェクトとして定義する(src/vending.machine.js)
// (略)
on: {
  INSERT_COIN: {
    // 「INSERT_COIN」イベントで「inserting」ステートへ遷移
    target: 'inserting', // (1)
  },
},
// (略)

 この記法を用いる場合、(1)のように target プロパティに遷移先のステート名を指定します。また、アクションやガード条件など、遷移に関連する追加の設定を行うこともできます。

ガード条件

 ガード条件は、特定の条件が満たされた場合にのみ状態遷移を許可する機能です。ガード条件は、cond プロパティを使用して定義されます(リスト7)。

[リスト7]ガード条件を定義する(src/vending.machine.js)
import { createMachine } from 'xstate';

// (2) 投入済みの金額をチェックする
const hasEnoughAmount = (context) => {
  // 投入金額が100円以上になっていればOK
  return context.amount >= 100;
};

const vendingMachine = createMachine({
  id: 'vendingMachine',
  initial: 'idle',
  context: {
    amount: 0, // (3) 投入済みの金額
  },
  states: {
    idle: {
      on: {
        INSERT_COIN: 'inserting',
      },
    },
    inserting: {
      on: {
        INSERT_COIN: "inserting",
        HAS_ENOUGH_AMOUNT: {
          target: 'ready',
          cond: hasEnoughAmount, // (1) ガード条件を定義
        },
      },
    },
    ready: {
      // hasEnoughAmountがtrueのときだけこのステートになれる
    },
    // その他のステートを定義
  },
});

 (1)で HAS_ENOUGH_AMOUNT イベントを発行できる条件( cond プロパティ)として、hasEnoughAmount 関数を登録しているので、(2)で実装した条件を満たす場合にのみイベントを発行できます。これにより、条件に応じた状態遷移を制御することができます。

 cond の実装には、(3)で定義した context の値を使用することが多いです。context はステートマシンの実行中に、どのステートからでも参照・更新が可能なデータの保存場所です。

 これで、ステートマシンの定義に関する基本的な知識が身につきました。初期ステート、状態遷移、イベント、ガード条件の設定方法を理解し、XStateを使って効果的にステートマシンを定義できるようになりました。

次のページ
アクションとサービス

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
現場で役立つ! React向けライブラリ詳説連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 中川幸哉(ナカガワユキヤ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/17739 2023/05/25 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング