複数のプラットフォーム(Web、モバイル、デスクトップ)で動作するアプリケーションにおいて、状態の一貫性と効率的な同期は重要な課題です。各環境の実行コンテキストが異なるため、データの隔離と共有のバランスを取る必要があります。
中心化ストアによる統一管理
状態を単一の信頼できるソースとして扱うことで、複雑な同期処理を回避できます。以下は、シンプルなカウンターストアの例です:
// 状態定義
const storeState = { counter: 0 };
// 更新ロジック
function updateCounter(action, state = storeState) {
switch (action.cmd) {
case 'ADD':
return { ...state, counter: state.counter + action.step };
case 'SUBTRACT':
return { ...state, counter: state.counter - action.step };
default:
return state;
}
}
リアクティブ更新の進化
手動での再描画から、依存関係を自動追跡するリアクティブモデルへ移行しています。代表的なライブラリには次のような特徴があります:
- Zustand:軽量でHookベース。React Nativeとの相性が良い。
- Jotai:原子的な状態分割により、再レンダリング範囲を最小化。
- Valtio:Proxyベースで直感的なミューテーションを可能に。
| ライブラリ | 同期方式 | 推奨用途 |
|---|---|---|
| Zustand | サブスクリプション | 中規模アプリ |
| Redux Toolkit | ミドルウェア駆動 | 大規模ビジネスロジック |
| BroadcastChannel API | ブラウザタブ間通信 | マルチウィンドウ同期 |
Reduxのクロスプラットフォーム最適化
プラットフォーム差異を吸収するため、アクションの正規化ミドルウェアを導入します:
const normalizeMiddleware = next => action => {
const standardized = {
type: action.type,
data: transformPayload(action.payload)
};
return next(standardized);
};
パフォーマンス向上策:
- メモ化セレクター(reselect)で重複計算を削減
- 非同期アクションにキャッシング機構を追加
- 動的Reducer注入で初期ロードを軽量化
MobXによる細粒度リアクティブ管理
観測可能なプロパティとアクションを明示的に宣言することで、副作用を制御します:
class ProfileStore {
profile = { name: '', age: 0 };
constructor() {
makeAutoObservable(this);
}
setName = (value) => {
this.profile.name = value;
};
}
| 最適化手法 | 適用シーン | 効果 |
|---|---|---|
| reaction分割 | 高頻度更新 | ★★★ |
| computedキャッシュ | 派生値計算 | ★★☆ |
Zustandによる軽量ステートシェアリング
プラットフォーム固有のストレージを抽象化して、一貫したAPIを提供します:
const useSession = create(
persist(
(set) => ({
token: '',
setToken: (val) => set({ token: val }),
clear: () => set({ token: '' })
}),
{
key: 'session',
storage: {
getItem: async (name) => {
return isNative ? await AsyncStorage.getItem(name) : localStorage.getItem(name);
},
setItem: async (name, value) => {
return isNative ? await AsyncStorage.setItem(name, value) : localStorage.setItem(name, value);
}
}
}
)
);
Piniaとミニプログラムの連携
Vueエコシステムとミニプログラム間で状態を橋渡しする方法:
const appStore = defineStore('app', {
state: () => ({ theme: 'light' }),
actions: {
toggleTheme() {
this.theme = this.theme === 'light' ? 'dark' : 'light';
if (typeof wx !== 'undefined') {
wx.setStorageSync('THEME_PREF', this.theme);
}
}
}
});
カスタム状態遷移機械の設計
ビジネスロジックを状態マシンとしてモデリングすることで、可読性と保守性を向上させます:
class WorkflowEngine {
#currentState = 'IDLE';
#transitions = {};
registerTransition(from, event, to) {
if (!this.#transitions[from]) this.#transitions[from] = {};
this.#transitions[from][event] = to;
}
dispatch(event) {
const next = this.#transitions[this.#currentState]?.[event];
if (next) {
this.#currentState = next;
return true;
}
return false;
}
}
| ユースケース | 開始状態 | トリガー | 終了状態 |
|---|---|---|---|
| 決済フロー | AUTH_PENDING | PAYMENT_OK | COMPLETED |
| ワークフロー | DRAFT | SUBMIT | REVIEWING |
リアルタイム同期のPub/Sub実装
WebSocketやRedis Pub/Subを利用して、複数クライアント間で即時同期を実現:
class SyncHub {
#channels = new Map();
subscribe(channel, handler) {
if (!this.#channels.has(channel)) {
this.#channels.set(channel, []);
}
this.#channels.get(channel).push(handler);
}
publish(channel, payload) {
const handlers = this.#channels.get(channel) || [];
handlers.forEach(fn => fn(payload));
}
}
オフライン時の状態復元
IndexedDBを使用して構造化データを永続化し、ネットワーク復帰時に自動同期:
async function initDB() {
return new Promise((resolve, reject) => {
const req = indexedDB.open('AppCache', 1);
req.onupgradeneeded = e => {
const db = e.target.result;
if (!db.objectStoreNames.contains('snapshots')) {
db.createObjectStore('snapshots', { keyPath: 'key' });
}
};
req.onsuccess = () => resolve(req.result);
req.onerror = reject;
});
}
競合解消戦略
最終書き込み勝ち(Last Write Wins)やベクトルクロックを用いた高度な整合性制御:
function mergeStates(local, remote) {
if (local.timestamp > remote.timestamp) {
return { ...local, synced: true };
} else {
return { ...remote, synced: true };
}
}
状態シャーディングによるパフォーマンス改善
巨大なグローバルステートを機能単位で分割し、必要なコンポーネントのみ更新通知:
const modularStore = {
auth: { user: null, isAuthenticated: false },
ui: { sidebarOpen: true, notifications: [] },
cache: { entities: {}, lastFetched: {} }
};
ProxyとWeakMapによる効率的監視
メモリリークを防ぎつつ、動的な依存追跡を実現:
const watchers = new WeakMap();
function reactive(target) {
return new Proxy(target, {
get(obj, prop) {
trackDependency(obj, prop);
return Reflect.get(obj, prop);
},
set(obj, prop, value) {
const result = Reflect.set(obj, prop, value);
triggerWatchers(obj, prop);
return result;
}
});
}
function trackDependency(obj, prop) {
// 現在のEffectを登録
}
function triggerWatchers(obj, prop) {
const fns = watchers.get(obj)?.[prop] || [];
fns.forEach(fn => fn());
}
フレームワーク非依存ミドルウェア
React、Vue、Svelteなど複数フレームワークに対応可能な共通インターフェース:
class UniversalStore {
#state = {};
#listeners = new Set();
getState() { return this.#state; }
setState(updater) {
this.#state = typeof updater === 'function' ? updater(this.#state) : updater;
this.#notify();
}
subscribe(listener) {
this.#listeners.add(listener);
return () => this.#listeners.delete(listener);
}
#notify() {
this.#listeners.forEach(fn => fn(this.#state));
}
}
エッジコンピューティングとの連携
5G/IoT時代における分散状態管理。工場や店舗のエッジノードでローカル処理を行い、クラウドと非同期同期:
- MQTTプロトコルによる低遅延通信
- KubeEdgeによるエッジクラスタ管理
- イベントドリブンアーキテクチャとの統合