svelte-firebase-state
Version:
Simplify Firebase integration in Svelte and SvelteKit with reactive state management for Firestore and Realtime Database.
148 lines (142 loc) • 4.38 kB
JavaScript
import {} from "firebase/auth";
import { ref, onValue, set, get } from "firebase/database";
import { RealtimeDatabaseState } from "./RealtimeDatabaseState.svelte.js";
export class NodeState extends RealtimeDatabaseState {
autosave;
// private firstFetchDone: boolean = false;
// private isUpdatingFromDB: boolean = true;
// private cleanup: () => void;
nodeRef;
constructor({ auth, database, path: pathFunctionOrString, listen = false, autosave = false }) {
super({
auth,
database,
listen,
pathFunctionOrString
});
this.autosave = autosave;
// this.cleanup = this.initialize_effects();
}
async init_ref() {
const pathStr = await this.get_path_string();
if (!pathStr) {
throw new Error("Path is not defined");
}
this.nodeRef = ref(this.database, pathStr);
}
listen_data() {
if (!this.nodeRef) {
throw new Error("nodeRef is not set");
}
this.unsub = onValue(this.nodeRef, (snapshot) => {
// this.isUpdatingFromDB = true;
this.dataState.value = snapshot.val();
// this.firstFetchDone = true;
}, (error) => {
console.error("NodeState.svelte | listen | error", error);
});
}
async fetch_data() {
if (!this.nodeRef) {
return null;
}
const snapshot = await get(this.nodeRef);
this.dataState.value = snapshot.val();
return this.dataState.value;
}
/*
// private initialize_effects(): () => void {
// return () => {};
// return $effect.root(() => {
// effect_deps(
// () => {
// console.log("effect_deps", this.data?.age);
// this.save_data_to_firebase();
// // this.initialize_effects();
// },
// () => [(this.data as any)?.age]
// );
$effect(() => {
console.log(this.data?.age);
});
$effect(() => {
if (!this.data) {
return () => console.log("$effect cleanup 1");
}
console.log("$effect", this.data.age);
if (!this.data || this.isUpdatingFromDB) {
this.isUpdatingFromDB = false;
return () => console.log("$effect cleanup 2");
}
console.log("SAVE VALUE");
this.save_data_to_firebase();
// this.initialize_effects();
//
return () => console.log("$effect cleanup 3");
});
// return () => console.log("$effect.root cleanup");
// });
//
// return $effect.root(() => {
// $effect(() => {
// console.log("$effect", this.data, this.isUpdatingFromDB);
//
// // Watch all keys in the object
// Object.keys(this.data || {}).forEach((key) => {
// console.log("key", key);
// });
//
// if (!this.data || this.isUpdatingFromDB) {
// this.isUpdatingFromDB = false;
// return () => {};
// }
//
// console.log("SAVE VALUE");
// this.save_data_to_firebase();
//
// return () => {};
// });
//
// return () => {};
// });
//
// return () => {};
// }
*/
save_data_to_firebase() {
if (!this.nodeRef || !this.data) {
return;
}
set(this.nodeRef, this.data);
}
set data(newValue) {
this.dataState.value = newValue;
if (this.autosave) {
this.save_data_to_firebase();
}
}
//!\ If set data is defined, we need to defined get data here as well
get data() {
return this.dataState.value;
}
save(key, update) {
if (!key) {
this.save_data_to_firebase();
return;
}
if (!update || !this.nodeRef || !this.data) {
return;
}
let newValue;
if (typeof update === "function") {
const updateFn = update;
const prevValue = this.data[key];
newValue = updateFn(prevValue);
}
else {
newValue = update;
}
this.data[key] = newValue;
this.save_data_to_firebase();
}
}