conf
conf copied to clipboard
Add unsubscribe method to Conf class
It's great that onDidChange
and onDidAnyChange
return functions to destroy the watcher, but it would be great to have the listeners be internal state and then provide an unsubscribe
method. This is especially nicer when you need to manage multiple Conf instances at once.
Before
let conf1 = undefined
let unsubscribeConf1 = undefined
let conf2 = undefined
let unsubscribeConf2 = undefined
export foo = () => {
if (unsubscribeConf1) unsubscribeConf1()
conf1 = new Conf(...)
unsubscribeConf1 = conf1.onDidAnyChange(...)
}
export bar = () => {
if (unsubscribeConf2) unsubscribeConf2()
conf2 = new Conf(...)
unsubscribeConf2 = conf2.onDidAnyChange(...)
}
After
let conf1 = undefined
let conf2 = undefined
export foo = () => {
if (conf1) conf1.unsubscribe()
conf1 = new Conf(...)
conf1.onDidAnyChange(...)
}
export bar = () => {
if (conf2) conf2.unsubscribe()
conf2 = new Conf(...)
conf2.onDidAnyChange(...)
}
Another, more sophisticated, approach, might be providing pause()
, stop()
, start()
methods allowing for more granular control over watching
I'm not really sold on this. You would only save a few characters, but it would introduce overhead both in the implementation, the docs, and more API surface for the developer to learn. I also don't think it's common to use multiple Conf instances.
Fair enough. I was able to achieve this fairly easily by just subclassing the conf object :)
Here is my subclass in-case anyone else wants this
/* eslint-disable functional/no-this-expression */
/* eslint-disable functional/no-class */
import Conf from "conf/dist/source"
import type {
OnDidAnyChangeCallback,
OnDidChangeCallback,
Unsubscribe,
} from "conf/dist/source/types"
export class Store<
T extends Record<string, any> = Record<string, unknown>
> extends Conf<T> {
// Manage subscriptions internally
readonly #subscriptions: Unsubscribe[] = []
public unsubscribe(): void {
if (!this.#subscriptions) return
this.#subscriptions.forEach((unsubscribe) => unsubscribe())
}
public onDidAnyChange(callback: OnDidAnyChangeCallback<T>): Unsubscribe {
const unsubscribe = super.onDidAnyChange(callback)
this.#subscriptions.push(unsubscribe)
return unsubscribe
}
public onDidChange<Key extends keyof T>(
key: Key,
callback: OnDidChangeCallback<T[Key]>,
): Unsubscribe {
const unsubscribe = super.onDidChange(key, callback)
this.#subscriptions.push(unsubscribe)
return unsubscribe
}
// alias "store" property to "current" to be more idiomatic with React Ref and
// because we're calling them Stores so we'd have Store.store otherwise
public get current(): T {
return this.store
}
public set current(value: T) {
this.store = value
}
}
I wonder if we could provide something that makes React integration easier though. Maybe a React hook or something. I'm always open to ideas on how to make it simpler to use.
I’m actually using it in electron, but inside a thread that doesn’t have access to app, so I’ve basically recreated a proxied version of electron-store. I just prefer the .current idiom from Ref over the .store one. The unsubscribe need for me is swapping config files (well really directories with the same files) based on the user. When you switch users, I want to unsubscribe from the old files and subscribe to the new ones
On Sun, Jan 3 2021 at 7:12 PM, Sindre Sorhus < [email protected] > wrote:
I wonder if we could provide something that makes React integration easier though. Maybe a React hook or something. I'm always open to ideas on how to make it simpler to use.
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub ( https://github.com/sindresorhus/conf/issues/131#issuecomment-753734345 ) , or unsubscribe ( https://github.com/notifications/unsubscribe-auth/AACXE4AZ2JLZDFXZPB5YJOLSYEW3RANCNFSM4VQFZFKA ).