0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

選択型ストーリーの状態管理 小さなオブジェクトと不変更新の例

0
Posted at

ブラウザで動く短い物語では、ストーリー全体よりも「いま何を選んだか」を明確に持つことが役立ちます。今回は四つの選択を持つUIを題材に、表示文章と選択状態を分ける最小のJavaScript例を紹介します。

着想の例は、非公式のファン作品 The Stolen Invitation の公開導入画面です。そこには任意の名前入力と「Four choices. One final bell.」という説明があります。以下のコードはこの記事のための独立した学習例であり、その作品の実装・実際の選択肢・ソースコードを再現したものではありません。

選択済みかどうかを文章から判定しない

文章そのものを状態として使うと、翻訳や表現の変更が判定条件に影響します。例では選択を A/B のIDとして保存し、表示文章は別に用意する前提にします。

function createDraft(alias = "") {
  return {
    alias: alias.trim().slice(0, 40) || "The Guest",
    choices: [null, null, null, null],
  };
}

function choose(draft, index, optionId) {
  if (!Number.isInteger(index) || index < 0 || index > 3) {
    throw new RangeError("index must be 0..3");
  }
  if (optionId !== "A" && optionId !== "B") {
    throw new TypeError("optionId must be A or B");
  }

  return {
    ...draft,
    choices: draft.choices.map((oldValue, i) =>
      i === index ? optionId : oldValue
    ),
  };
}

function isComplete(draft) {
  return draft.choices.every((value) => value === "A" || value === "B");
}

let draft = createDraft("Guest");
draft = choose(draft, 0, "A");
draft = choose(draft, 1, "B");
draft = choose(draft, 2, "A");
draft = choose(draft, 3, "B");
console.log(isComplete(draft)); // true

この小さな例では、入力可能な位置と選択IDを関数の入口で限定しています。UIや将来の変更によって不正な位置や選択IDが渡されたときに、早く発見するためです。保存データを復元する場合の構造検証は、この例には含めていません。実際の作品では、選択肢IDを物語の設計に合わせて定義します。

更新前の状態を残す

choose は元の配列を変更せず、新しい配列を返します。更新前と更新後の差を確認できるので、「戻る」「やり直す」の設計でも、どの時点の状態を保存するかを決めやすくなります。この例自体には履歴機能は実装していません。

任意の名前はHTMLとして扱わない

名前を画面に表示する際は、プレーンテキストとして扱います。

nameElement.textContent = draft.alias;

名前を文字列連結した innerHTML に渡す必要はありません。また「端末内だけに保存」と説明するなら、URL、計測イベント、外部APIにも名前を送っていないか、別途確認が必要です。参照作品のネットワークや保存方式を監査したという意味ではありません。

確認する境界

  • 負の位置、4以上の位置、小数の位置を拒否する。
  • A/B以外の値を拒否する。
  • 一つの選択で別の位置が変わらない。
  • 更新前のドラフトが変更されない。
  • 四つを選び終えるまで完成扱いにしない。

この記事の最初のコードブロックはNode.js v24.19.0で実行し、上記の入力境界、元の配列が変わらないこと、未完了と完了の判定を確認しました。DOMの表示例や参照作品全体をE2Eテストしたという意味ではありません。

大きなエンジンを先に作るより、まず選択状態を明示し、画面の文章から分離すると、短い物語でも検証箇所をはっきりさせられます。

開示:この記事はAIで作成した技術解説で、参照した非公式ファン作品を紹介する目的も含みます。コードは独立した学習例です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?