Vuex,firestore:显示过滤结果

Posted

技术标签:

【中文标题】Vuex,firestore:显示过滤结果【英文标题】:Vuex, firestore: Show the filtered result 【发布时间】:2021-02-05 06:53:27 【问题描述】:

我想将过滤功能添加到我的项目中。 现在我有了一个按钮组件来触发过滤器搜索。

如果我按下餐厅按钮,结果将是风暴中具有“餐厅”值的商店。

另一方面,如果我按下超市按钮,结果将是firestore中具有“超市”价值的商店。

现在我正在使用 vuex,我正在使用 Result.vue 中的 mapGetters 从“getMenuItems”中检索数据。

我在 Buttons.vue 中添加的方法是触发突变。 如果我按下餐厅按钮,餐厅数据将被推送到 menu.js 中的“restaurantItems”中。

我想要实现的是,如果我按下餐厅按钮,Result.vue 将读取“restaurantItems”而不是“getMenuItems”。

我尝试在 Result.vue 的计算属性中使用 if 语句,但找不到解决方案。

如果我的方法是错误的,我很高兴你告诉我正确的方法。

Buttons.vue

<template>
    <div>
        <section class="button-section">
            <div class="d-flex buttons">
                <b-button class="supermarket" @click.prevent="showSupermarket">Supermarket</b-button>
                <b-button class="restaurant" @click.prevent="showRestaurant">Restaurant</b-button>
        </div>
        </section>
    </div>
</template>

<script>
import fireApp from '@/plugins/firebase'
const firebase = require("firebase");
require("firebase/firestore");
const db = firebase.firestore();
import  mapGetters  from 'vuex'
import store from '../store'

    export default 
        name: 'Buttons',
        data() 
            return 
                supermarket: "",
                restaurant: ""
            
        ,
        methods: 
            showSupermarket() 
                const supermarketRef = db.collection('Product').where('type', '==', "Supermarket")
                supermarketRef.get()
                    .then(snapshot => 
                    if (snapshot.empty) 
                    console.log('No matching documents.');
                    return;
                    
                    snapshot.forEach(doc => 
                        const supermarket = doc.data()
                        console.log(supermarket)
                        this.supermarket = supermarket
                        //triger mutation here.
                        this.$store.commit('showSupermarketResult', this.supermarket)
                        //console.log(doc.id, '=>', doc.data());
                    );
                )
                .catch(err => 
                    console.log('Error getting documents', err);
                );
            ,
            showRestaurant() 
                const restaurantRef = db.collection('Product').where('type', '==', "Restaurant")
                restaurantRef.get()
                    .then(snapshot => 
                    if (snapshot.empty) 
                    console.log('No matching documents.');
                    return;
                    
                    snapshot.forEach(doc => 
                        const resutaurant = doc.data()
                        console.log(resutaurant)
                        this.resutaurant = resutaurant
                        this.$store.commit('showRestaurantResult', this.resutaurant)
                        //console.log(doc.id, '=>', doc.data());
                    );
                )
                .catch(err => 
                    console.log('Error getting documents', err);
                );
            ,
        
    
</script>

Result.vue

<template>
    <div>
    <Navbar />
    <Map />
    <Buttons />
    
    <div class="main">
        
        <section class="cards">
        <div class="card" v-for="(item, index) in getMenuItems" :key="index">
            <div class="card-icons" v-if="item.quantity > 0">
            <div class="card-icon">
            <div class="card__image-container" v-for="(sample, index) in item.sample" :key="index">
                <!-- <router-link to="/product"> -->
                <router-link :to="name:'Product',params:id:item.id">
                <img
                :src="sample"
                
                />
                </router-link>
                <div class="card__content">
                    <div class="card__info">
                        <span class="text--medium"> item.business </span>
                        <span class="card__distance text--medium"> item.quantity  left</span>
                    </div>
                </div>
            </div>
            </div>
            <div class="icons">
            <div class="time">
                <span>until<br> item.limitObject </span>
                </div>
                <div class="fav">
                <span>Heart</span>
                </div>
                <div class="price">
                <span> item.initial <br> item.sale </span>
                </div>
            </div>
            </div>
        </div>
        </section>
    </div>
    </div>
</template>

<script>
import axios from 'axios';
import Navbar from "@/components/Navbar.vue";
import Buttons from "@/components/Buttons.vue";
import Map from "@/components/Map.vue";
import fireApp from '@/plugins/firebase'
const firebase = require("firebase");
require("firebase/firestore");
const db = firebase.firestore();
import  mapGetters  from 'vuex'


    export default 
        name: "UserLocation",
        data() 
            return 
                address: "",
                error: "",
                spinner: false
            
        ,
        components: 
            Navbar,
            Map,
            Buttons
        ,
        created() 
            //vuexfire
            const dbMenuRef = db.collection('Product')
            this.$store.dispatch('setMenuRef', dbMenuRef)
        ,        
        computed: 
            ...mapGetters([
                'getMenuItems'
            ])
        ,
        methods: 
            
        
    
</script>

menu.js

import  firestoreAction  from 'vuexfire'
import fireApp from '@/plugins/firebase'
const firebase = require("firebase");
require("firebase/firestore");
const db = firebase.firestore();

const dbMenuRef = db.collection('Product')

const state = 
    menuItems:[],
    supermarketItems:[],
    restaurantItems: [],
    store:[]


const getters = 
    getMenuItems: state => state.menuItems,
    supermarketItems: state => state.supermarketItems,
    restaurantItems: state => state.restaurantItems


const mutations = 
    showSupermarketResult(state, supermarket) 
        state.menuItems.push(supermarket);
    ,
    showRestaurantResult(state, restaurant) 
        state.restaurantItems.push(restaurant);
    ,


const actions = 
    setMenuRef: firestoreAction(context => 
        return context.bindFirestoreRef('menuItems', dbMenuRef)
    ),
    


export default 
    state,
    mutations,
    getters,
    actions

【问题讨论】:

【参考方案1】:

我会重构问题中的大部分代码,因为其中许多是重复的,例如:

Buttons.vue:重构按钮操作

<b-button class="supermarket" @click.prevent="showCollection('supermarket')">Supermarket</b-button>
<b-button class="restaurant" @click.prevent="showCollection('restaurant')">Restaurant</b-button>

Buttons.vue:重构方法

methods: 
    showCollection(type) 
        this.$store.dispatch('setCollectionType', type)
    

menu.js:将 firestore 逻辑移动到操作中,有副作用

const state = 
    ...,
    currentType: 'menu'

const mutations = 
    ...,
    setCurrentType(state, type) 
        state.currentType = type
    

const actions = 
    ...
    setCollectionType: ( commit, state , type) 
        commit('setCurrentType', type)
        const mutations = 
            supermarket: 'showSupermarketResult',
            restaurant: 'showRestaurantResult'
        
        const states = 
            supermarket: 'supermarketItems',
            restaurant: 'restaurantItems'
        
        if (state[states[type]].length) return
        const collectionRef = db.collection('Product').where('type', '==', type)
        collectionRef.get()
            .then(snapshot => 
                if (snapshot.empty) 
                    console.log('No matching documents.');
                    return;
                
                snapshot.forEach(doc => 
                    const data = doc.data()
                    commit(mutations[type], data)
                );
            )
            .catch(err => 
                console.log('Error getting documents', err);
            );
        ,
    

Result.vue:最后,重构如何显示结果

<div class="card" v-if="currentType === 'supermarket'" v-for="(item, index) in supermarketItems" :key="index">
    <!-- Iterate supermarket items-->
</div>
<div class="card" v-if="currentType === 'restaurant'" v-for="(item, index) in restaurantItems" :key="index">
    <!-- Iterate restaurant items-->
</div>

【讨论】:

并且每次按下按钮时,都会将项目添加到数组中。我想我需要解决这个问题。 @YoheiUmezu 你可以随时取消menu.js上不必要的数据更新,看我更新的答案

以上是关于Vuex,firestore:显示过滤结果的主要内容,如果未能解决你的问题,请参考以下文章

在 Firestore REST API 中查询嵌套对象

SwiftUI + Firestore - 基于从 Firestore 返回的数组的过滤器列表

如何从 Vuex 商店中删除 Firestore 快照侦听器

在 vuex 操作中访问 this.$fireStore (Nuxt.js)

Firestore、vue、vuex、vuexfire:如何让 getter 真正从存储中获取数据?

Vue,firestore:合并集合后如何显示 LIVE 数据