Как я могу визуализировать состояние Vuex в зависимости от срабатывания функции?

avatar
Rafael Oviedo
8 августа 2021 в 23:57
41
2
0

Я видел, что есть пара подобных вопросов, но мне не удалось с ними справиться, поэтому я задам свой собственный.

Дело в следующем. У меня есть состояние "allCountries", которое представляет собой массив и изначально заполнено объектами 250 стран. Я правильно отображаю эти страны в своем домашнем компоненте, дело в том, что я хочу фильтровать при нажатии кнопки страны для континента, который представляет кнопка. Например, если на кнопке написано «Европа», я хочу получить все страны, где свойство «континент» — Европа.

Я достиг этого с помощью следующего кода:

const store = createStore({
state: {
    allCountries: [],
    filteredCountries: [],
    countryId: {},
},

mutations: {

    filterByContinent(state, payload) {
        let countries = [...state.allCountries];
        state.filteredCountries = countries.filter(
            (country) => country.continent === payload
        );
    },
},

Проблема в том, что я не знаю, как отобразить отфильтрованные страны при нажатии кнопки, в инструментах vuex dev я вижу, как состояние "filteredCountries" заполняется правильными странами континента при нажатии.

Я пробовал это, но не работает:

<template>
<div>
    <!-- <p class="homeTitle">COUNTRIES:</p> -->
    <ul class="countriesBox" v-if="allCountries">
        <li
            v-for="country in allCountries"
            :key="country.id"
            class="countryCard"
        >
            <br />
            <router-link
                :to="{
                    name: 'CountryDetail',
                    params: { id: country.Id },
                }"
                class="countryName"
                >{{ country.name }}</router-link
            >
            <br />
            <p class="countryContinent">{{ country.continent }}</p>
            <br />
            <img
                :src="`${country.flagImage}`"
                alt="country flag"
                class="flagImage"
            />
        </li>
    </ul>

    <ul class="countriesBox" v-else-if="filteredCountries">
        <li
            v-for="country in filteredCountries"
            :key="country.id"
            class="countryCard"
        >
            <br />
            <router-link
                :to="{
                    name: 'CountryDetail',
                    params: { id: country.Id },
                }"
                class="countryName"
                >{{ country.name }}</router-link
            >
            <br />
            <p class="countryContinent">{{ country.continent }}</p>
            <br />
            <img
                :src="`${country.flagImage}`"
                alt="country flag"
                class="flagImage"
            />
        </li>
    </ul>

    <div class="backAndForwardButtons">
        <button>&#10094;</button>
        <button>&#10095;</button>
    </div>

    <FiltersBar />
</div>
</template>

Я правильно сопоставляю состояния с

import { mapState } from "vuex";
import store from "../store";

export default {
    name: "HomePage",
    computed: {
        ...mapState(["allCountries"]),
        ...mapState(["filteredCountries"]),
    },
};

если кто-то может помочь, буду очень благодарен.

Источник

Ответы (2)

avatar
yaiks
9 августа 2021 в 00:49
0

Вы можете создать геттер, проверяющий наличие от .length до filteredCountries. Если нет, по умолчанию используется allCountries, например:

.
countries(state) {
  return state.filteredCountries.length ? state.filteredCountries : state.allCountries
}

Тогда в вашем компоненте вам не нужно копировать логику для отображения двух отдельных списков, поступающих из двух разных источников данных. Просто нужно использовать один источник данных, который в данном случае я назвал countries

.
Rafael Oviedo
9 августа 2021 в 01:18
1

Вы мастер! Спасибо, ваш ответ решил мою проблему!

avatar
Kim Rop
9 августа 2021 в 00:33
0

геттер магазина для отфильтрованных стран может выглядеть примерно так

filteredCountries: (state) => cont => {
      return state.countries.filter(country=>{
       return country.continent===cont
    })
}

ну может код не такой точный но я думаю идея осталась прежней

как вы можете видеть, у геттера filteredCountries есть дополнительный аргумент, куда направляется выбранный вами континент

затем в вашем компоненте

data(){
   return {
       cont_filter:"europe"
   }
}

надеюсь, изменить значение на cont_filter не проблема, потому что это то, что вы хотите изменить при нажатии кнопки. теперь вы можете использовать это просто так

    <li v-for="country in filteredCountries(cont_filter)"
                :key="country.name">
        {{country.name}}
   </li>