【问题标题】:Firebase: Why value event gets fired before new child ref gets addedFirebase:为什么在添加新子引用之前触发值事件
【发布时间】:2019-05-25 18:16:03
【问题描述】:

以下代码,是一个非常简单的 Firebase - VueJS 应用,(codeSandBox demo)

app.vue

<template>
  <div class="container">
    <!-- Adding Quote -->
    <add-quote/>

    <!-- Display Quotes -->
    <quote-list/>
  </div>
</template>

<script>
import addQuote from "./components/AddQuote.vue";
import quoteList from "./components/QuoteList.vue";

export default {
  components: {
    addQuote,
    quoteList
  },
  methods: {
    get_allQuotes: function() {
      // var vm = this;
      var localArr = [];
      quotesRef
        .once("value", function(snapshot) {
          snapshot.forEach(function(snap) {
            localArr.push({
              key: snap.key,
              category: snap.val().category,
              quoteTxt: snap.val().quoteTxt
            });
          });
        })
        .then(data => {
          this.$store.commit("set_allQuotes", localArr);
        });
    }
  },
  mounted() {
    this.get_allQuotes();
    console.log("App: mounted fired");
  }
};
</script>

store.js(vuex 商店)

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export const store = new Vuex.Store({
    state: {
        quotesList: []
    },
    getters: {
        get_quotesList(state) {
            return state.quotesList;
        }
    },
    mutations: {
        set_allQuotes(state, value) {
            state.quotesList = value;
        }
    }
});

AddQuote.vue

<template>     
    <div class="row quote-edit-wrapper">         
        <div class="col-xs-6">           
            <textarea v-model.lazy="newQuoteTxt" 
                rows="4" 
                cols="50"></textarea>
            <button @click="addQuote">Add Quote</button>
        </div>
    </div>
</template>

<script>

export default {   
  data() {
    return {
            newQuoteTxt: '',
      }
    },
    computed: {
    allQuotes() {
      return this.$store.getters.get_quotesList;
        },
        newQuoteIdx() {
            var localArr = [...this.allQuotes]

            if(localArr.length > 0) {
                var highestKEY, currKEY

                localArr.forEach((element, idx) => {
                    currKEY = parseInt(element.key)
                    if(idx == 0) {
                        highestKEY = currKEY
                    } else {
                        if(highestKEY < currKEY) {
                            highestKEY = currKEY
                        }
                    }
                })
                return highestKEY + 1
            } else {
                return 1
            }
        }
    },
  methods: {
        // ADD new Quote in DB
    addQuote: function() {
            var vm = this
            var localArr = [...this.allQuotes]

            //1. First attach 'value' event listener,
            // Snapshot will contain data from that ref 
            // when any child node is added/updated/delete
            quotesRef.on('value', function (snapshot) {
                snapshot.forEach(function(snap) {
                var itemExists = localArr.some(function (item, idx) {
                        return item.key == snap.key
                    })
                // If newly added item doesn't yet exists then add to local array
                if (!(itemExists)) {
                    localArr.push({
                        key: snap.key,
                        category: snap.val().category,
                        quoteTxt: snap.val().quoteTxt })

                    vm.$store.commit('set_allQuotes', localArr)
                    }
                })
            })

            //2. Second set/create a new quotes in Firebase, 
            // When this quote gets added in Firebase,
            // value event (attached earlier) gets fired  
            //  with 
            var newQuoteRef = quotesRef.child(this.newQuoteIdx)
            newQuoteRef.set({
                category: 'motivation',
                quoteTxt: this.newQuoteTxt
            })
        }
    }
}
</script>

quoteList.vue

<template>
    <div class="row">
        <div class="col-xs-12 quotes-list-wrapper">
            <template v-for="(quote,idx) in allQuotes">

                <!-- Quote block -->
                    <div class="quote-block-item">
                        <p class="quote-txt"> {{quote.quoteTxt}} </p>
                    </div>
            </template>
        </div>
    </div>  
</template>

<script>
    export default {
        computed: {
            allQuotes() {
                return this.$store.getters.get_quotesList;
            }
        }
    }

</script>

注意:主要关注的代码是addQuote.vue

用户输入newQuoteTxt,该newQuoteTxt 作为quotesRef 下的报价项目添加到Firebase (addQuote())。一旦添加报价(在 firebase 上),Firebase 客户端 SDK 的 value 事件就会触发,并将新报价(通过回调)添加到 localArray (allQuotes)。 VueJS 然后用新添加的 Quote 更新 DOM。

addQuote() 方法的工作方式如下:

  1. 首先,将回调/侦听器附加到quotesRef 上的“值”事件
quotesRef.on('value', function (snapshot) {
   ....
})

  1. 接下来,使用 ID this.newQuoteIdx 创建一个 firebase ref(quotesRef 的子代)

    var newQuoteRef = quotesRef.child(this.newQuoteIdx)

然后(在这个新创建的 Ref 上)调用 set(),将 newquote 添加到 firebase RealTime DB。

  1. value 事件被触发(从步骤 1 附加)并调用监听器 /callback。

回调通过匹配 localArr 和 snap.key 的键在现有项目列表中查找此新报价的键,如果未找到,则将新报价添加到 localArr。 localArr 提交到 vuex 存储。

`vm.$store.commit('set_allQuotes', localArr)`

VueX 然后更新这个数组的所有订阅者组件。然后 VueJS 将新引号添加到现有的引号列表中(更新 DOM)

在调试 addQuote 方法时,我注意到的问题是,脚本的执行/流程(通过 chrome 调试器中的 F8)首先进入附加到 value 事件的侦听器/回调,然后添加代码 newQuoteRef.set({ ... })新报价(在 firebase 上),这反过来会触发 'value' 事件。

我不确定为什么会发生这种情况。 anybuddy 可以解释为什么在创建引号之前调用侦听器/回调。

(QuotesRef 的)子节点是否缓存在客户端,这样即使在添加新报价之前,'value' 也会触发。

谢谢

【问题讨论】:

    标签: firebase vue.js firebase-realtime-database vuejs2


    【解决方案1】:

    如果我正确理解了您的问题(您的代码不是很容易理解!:-))这是正常行为。如documentation 中所述:

    值事件将触发一次,初始数据存储在 这个位置,然后每次数据再次触发 变化

    您的沙盒演示实际上并未展示应用程序的工作原理,但通常您不应在将新节点保存到数据库的方法中设置侦听器。这两件事应该解耦。

    一种常见的方法是在组件的created 挂钩中设置侦听器(请参阅https://vuejs.org/v2/guide/instance.html#Instance-Lifecycle-Hookshttps://vuejs.org/v2/api/#created),然后在您的addQuote 方法中写入数据库。一旦你写了,监听器就会被解雇。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-08
      • 2014-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-19
      • 2012-05-24
      • 1970-01-01
      相关资源
      最近更新 更多