ホームページ  >  記事  >  ウェブフロントエンド  >  Javascript を使用してリアクティブ ストアを最初から構築する

Javascript を使用してリアクティブ ストアを最初から構築する

DDD
DDDオリジナル
2024-11-04 11:32:02989ブラウズ

リアクティブ プログラミングは、データの変更を動的に反映するアプリケーションを作成できる優れたアプローチです。これは、React や Vue などの多くの最新の JavaScript フレームワークの背後にあるコア技術であり、ユーザーのアクションやその他の状態の変化に応じて更新されます。リアクティブの内部にあるものを理解するのは多大な労力のように感じるかもしれませんが、それはフレームワークの「魔法」の抽象化の 1 つであるように感じられます。しかし、小さなリアクティブ システムを自分で構築して、それが実際にどのように機能するかを確認できたらどうでしょうか?

この記事では、JavaScript でシンプルなリアクティブ ストアを最初から構築することで、リアクティブ プログラミングの基本を説明します。依存関係の追跡や自動更新などの主要な概念を最小限の実装で説明します。最終的には、依存関係を自動的に追跡し、状態が変化するたびに更新をトリガーするリアクティブなデータ構造を作成する方法を理解できるはずです。このアプローチは、反応性を理解するのに役立ち、それを自分で実験し、場合によってはプロジェクトに適用するためのツールを提供します。

使用するリアクティブ システムのコア コンポーネントを見てみましょう。

  • エフェクト: リアクティブ データの変更に応じて自動的に実行される関数。これらは、アクセスされた信号の依存関係を追跡するエフェクト関数を使用して登録されます。
  • シグナル: 値が変更されるたびに依存効果を通知するリアクティブ データ プロパティ。
  • 依存関係: シグナルとそれに依存するエフェクトの間の関係。依存関係は追跡され、信号の変化が関連するエフェクトの更新をトリガーします。

リアクティブ プログラミングの定義は終わったので、使用する Javascript API についても触れておきましょう。

プロキシ: Proxy オブジェクトを使用すると、別のオブジェクトのプロキシを作成でき、基本的な操作 (プロパティ アクセスや割り当てなど) のカスタム動作を定義できます。このコードでは、リアクティブ ストア (状態オブジェクト) を変更に応答させるために使用されます。

Reflect: Reflect API は、インターセプト可能な JavaScript 操作のメソッドを提供します。これは、リアクティブ関数で Reflect.get や Reflect.set などの操作を実行するために使用されます。これにより、プロキシがオブジェクトの元の動作を維持しながら、プロパティへのアクセスと割り当てを処理できるようになります。

Map: Map オブジェクトは、キーと値のペアを保持するコレクションです。キーには任意のデータ型を指定できます。この実装では、各信号に関連付けられた依存関係を追跡する dependencyMap を作成するために使用されます。

さて、初期状態がどのようになるかを定義してみましょう:

// Let's define a Map object to track our dependencies
const dependencyTrackerMap = new Map();
// The activeEffect variable will hold the currently executing 
// effect function. 
// It will be set when an effect is run and will be used
// to track which effects depend on specific reactive properties. 
let activeEffect = null

// This function will make an object reactive
function reactive(target) {
    return new Proxy(target, {
        get(obj, prop) {
            trackDependency(prop); // Track dependency
            return Reflect.get(obj, prop);
        },
        set(obj, prop, value) {
            const result = Reflect.set(obj, prop, value);
            triggerDependency(prop); // Trigger reactions
            return result;
        }
    });
}

// the effect function will register reactive functions
function effect(fn) {
    activeEffect = fn;
    fn(); // Run the function once to register dependencies
    activeEffect = null;
}

// this function will track dependencies
function trackDependency(key) {
    if (activeEffect) {
        if (!dependencyTrackerMap.has(key)) {
            dependencyTrackerMap.set(key, new Set());
        }
        dependencyTrackerMap.get(key).add(activeEffect);
    }
}

// this function will trigger dependencies
function triggerDependency(key) {
    const deps = dependencyTrackerMap.get(key);
    if (deps) {
        deps.forEach(effect => effect());
    }
}

// This will create a reactive object with an initial state
// count and message here are signals
const state = reactive({ count: 0, message: "Hello" });

それで、私たちがやったことは次のとおりです:

  1. オブジェクトを受け取り、将来オブジェクトに加えられる変更を追跡するプロキシを返すリアクティブ関数を作成しました
  2. 状態に依存するリアクティブ関数を登録するエフェクト関数を作成しました。エフェクトが定義されると、すぐに実行されて依存関係が登録され、それに応じて activeEffect が設定されます。
  3. 私たちは 3 つの部分で構成される依存関係トラッカーを作成しました。 trackDependency 関数は、リアクティブ プロパティにアクセスしたときにアクティブな効果があるかどうかを確認します。 「はい」の場合、その効果は、dependencyTrackerMap の対応するプロパティの依存関係のセットに追加されます。次に、triggerDependency 関数は、プロパティに関連付けられた依存効果のセットを dependencyTrackerMap から取得し、プロパティ値が変更されたときにそれぞれを実行します。

次に、コールバックを使用してエフェクトを作成し、それをトリガーしてみましょう:

// Let's define a Map object to track our dependencies
const dependencyTrackerMap = new Map();
// The activeEffect variable will hold the currently executing 
// effect function. 
// It will be set when an effect is run and will be used
// to track which effects depend on specific reactive properties. 
let activeEffect = null

// This function will make an object reactive
function reactive(target) {
    return new Proxy(target, {
        get(obj, prop) {
            trackDependency(prop); // Track dependency
            return Reflect.get(obj, prop);
        },
        set(obj, prop, value) {
            const result = Reflect.set(obj, prop, value);
            triggerDependency(prop); // Trigger reactions
            return result;
        }
    });
}

// the effect function will register reactive functions
function effect(fn) {
    activeEffect = fn;
    fn(); // Run the function once to register dependencies
    activeEffect = null;
}

// this function will track dependencies
function trackDependency(key) {
    if (activeEffect) {
        if (!dependencyTrackerMap.has(key)) {
            dependencyTrackerMap.set(key, new Set());
        }
        dependencyTrackerMap.get(key).add(activeEffect);
    }
}

// this function will trigger dependencies
function triggerDependency(key) {
    const deps = dependencyTrackerMap.get(key);
    if (deps) {
        deps.forEach(effect => effect());
    }
}

// This will create a reactive object with an initial state
// count and message here are signals
const state = reactive({ count: 0, message: "Hello" });

作成した状態を更新しようとすると、コンソール ログがトリガーされます:

//We are using state from the previous snippet:
effect(() => {
    console.log(Count has changed: ${state.count});
});

effect(() => {
    console.log("Message has changed");
    console.log(The new message is: ${state.message});
});

依存関係がトリガーされたときに何が起こるかを少し視覚的に示します。

Build a reactive store from scratch using Javascript


この記事では、JavaScript で基本的なリアクティブ システムを作成し、データの変更に応じた自動更新 (または副作用) を可能にする方法を検討しました。この実装は、フレームワーク「マジック」の一部であるリアクティブ プログラミングの概念への入門として機能します。さらに、Proxy API と Reflect API が何をするのかを学び、それらと Map オブジェクトを使用しました。

要約すると、このリアクティブ システムは依存関係を管理し、状態が変化したときにエフェクトを自動的に更新します。特定のリアクティブ プロパティに依存する関数を登録すると、システムはどの関数がどのプロパティに依存するかを追跡し、必要に応じて再実行します。このアプローチにより、コードを追加することなく状態の変更が自動的に UI に反映される応答性の高いアプリケーションを作成でき、開発者のエクスペリエンスが向上し、データ処理がより簡単かつ効率的になります。

以上がJavascript を使用してリアクティブ ストアを最初から構築するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。