JavaScriptProviderPatternSnippet
以下のコードは JavaScript でRiverpodのようなProviderPatternを実装した例である。
このコードを概略↓ノートはJavaScriptで作成するProviderPattern解剖図にて。
class ProviderContainer {
constructor() {
if(!ProviderContainer.instance){
ProviderContainer.instance = this;
}
this._providers = new Map();
this._dependencies = new Map();
this._listeners = new Map();
return ProviderContainer.instance;
}
createProvider(createFn) {
const provider = new ProviderCore(
createFn,
null,
false
);
return provider;
}
read(provider) {
if (!provider._isInitialized) {
const ref = this._createRef(provider);
provider._value = provider._create(ref);
provider._isInitialized = true;
}
return provider._value;
}
watch(provider, listener) {
if (!this._listeners.has(provider)) {
this._listeners.set(provider, new Set());
}
this._listeners.get(provider).add(listener);
listener(this.read(provider));
return () => {
this._listeners.get(provider).delete(listener);
};
}
update(provider, updateFn) {
const currentValue = this.read(provider);
const newValue = updateFn(currentValue);
provider._value = newValue;
provider._isInitialized = true;
this._notifyListeners(provider, newValue);
}
_notifyListeners(provider, newValue) {
const listeners = this._listeners.get(provider);
if (listeners) {
listeners.forEach(listener => listener(newValue));
}
}
_createRef(currentProvider) {
const ref = {
watch: (otherProvider) => {
return this.read(otherProvider);
},
update: (updateFn) => {
this.update(currentProvider, updateFn);
}
};
return ref;
}
}
class ProviderCore {
constructor(createFn) {
this._create = createFn;
this._value = null;
this._isInitialized = false;
}
}
// コンテナの作成
const PROVIDER_COTAINER = new ProviderContainer();
const container = new ProviderContainer();
// 数値プロバイダーの作成
const counterProvider = container.createProvider((ref) => {
return 0;
});
// ユーザープロバイダーの作成
const userProvider = container.createProvider((ref) => {
return { name: '太郎', age: 30 };
});
// 派生プロバイダーの例
const userNameProvider = container.createProvider((ref) => {
const user = ref.watch(userProvider);
return user.name;
});
// 値の読み取り
console.log(container.read(counterProvider)); // 0
// 値の監視
const unsubscribe = container.watch(counterProvider, (value) => {
console.log('値の変更を検知:', value);
});
// 値の更新
container.update(counterProvider, (currentValue) => currentValue + 1);
//派生プロバイダーの使用
console.log(container.read(userNameProvider));// '太郎'