这是创建双向绑定到 Firebase Realtime 数据库路径的 Svelte 5 存储的正确方法吗?

问题描述 投票:0回答:1

这就是我在 Svelte 4 中的做法:

// $lib/firebase.ts
export function writableRealtimeStore<T>() {
  let unsubscribe: () => void = () => {}
  let objectRef: any

  const store = writable<T | null>(null)
  let storeSet = store.set

  return {
    subscribe: store.subscribe,
    set: (value: any) => {
      return set(objectRef, value)
    },
    update: () => {},
    setPath: (path: string) => {
      objectRef = ref(realtimeDB, path)
      unsubscribe()
      unsubscribe = onValue(objectRef, (snapshot) => {
        storeSet((snapshot.val() as T) ?? null)
      })
    },
  }
}

// $lib/stores.ts
export const myStore = writableRealtimeStore()

// routes/+page.svelte
<script lang="ts">
    import { myStore } from '$lib/stores'
    myStore.setPath('/books/<book_id>')
</script>

<input type="text" bind:value={myStore.bookName}

此存储是双向响应的 - 当数据库中的值发生变化时,它会更新 UI,而当用户更新输入的值时,数据库也会发生变化。我可以直接访问数据库对象的属性

myStore.bookName

但是使用 Svelte 5 我无法获得商店对象的相同行为:

// $lib/firebase.ts
export function createRealtimeStore<T>() {
    let unsubscribe = () => {}
    let store: { value: T | undefined } = $state({ value: undefined })
    let _ref: DatabaseReference

    return {
        get value(): T | undefined {
            return store.value
        },
        update: () => {
            if (_ref) set(_ref, store.value)
        },
        setPath: (path: string) => {
            _ref = ref(realtime, path)
            unsubscribe()
            unsubscribe = onValue(_ref, (snapshot) => {
                store.value = snapshot.val()
            })
        },
        unsubscribe,
    }
}

// $lib/stores.ts
export let myStore = createRealtimeStore()

// routes/+page.svelte
<script lang="ts">
    import { myStore } from '$lib/stores'

    myStore.setPath('/books/<book_id>')

    $effect(() => {
        if (project.value) {
            project.update()
        }
    })
</script>

<input type="text" bind:value={myStore.value.bookName}

两个问题:

  1. 我必须使用商店的道具,例如
    myStore.value.bookName
    ,而不是清洁工
    myStore.bookName
  2. $effect
    符文必须位于页面中,而不是在创建商店的函数中,因为
    $effect
    只能在组件初始化期间调用,否则会出现错误。

总的来说,Svelte 4 的做法更加干净,使用起来也很愉快,我不相信你不能用新的、据称经过改进的商店系统做同样的事情。

javascript firebase firebase-realtime-database svelte sveltekit
1个回答
0
投票
  1. 您仍然可以使用

    myStore.bookName
    ,尽管这需要在状态对象上传播数据。要判断数据是否已实际加载,您可能需要一个单独的标志。

    Object.assign(store, snapshot.val());
    
    在这种情况下,还会从状态对象中单独返回各种函数,这样就不会发生冲突。这是否比使用

    value

     包装更好还有待商榷。

  2. 您可以通过

    $effect.root

    在创建商店的函数中创建独立的效果范围。
    

© www.soinside.com 2019 - 2024. All rights reserved.