【问题标题】:Why the slice method doesn't work on array prop?为什么 slice 方法对 array prop 不起作用?
【发布时间】:2023-02-09 06:35:12
【问题描述】:

我有以下定义 Pinia 存储的代码:

import { ref, computed, shallowRef } from 'vue'
import { defineStore } from 'pinia'

export const usePokemonStore = defineStore('pokemons', () => {
    // define the pokemons list state
    const pokemonsList = ref([]);
    const pokemonsLoaded = ref([]);
    const pokemonsLoadedNames = ref([]);

    // computed
    const pokemonsListLength = computed(() => pokemonsList.value.length)
    const pokemonsLoadedLength = computed(() => pokemonsLoaded.value.length)

    // actions
    async function getList() {
        const res = await fetch('https://pokeapi.co/api/v2/pokemon?limit=100000&offset=0');
        const data = await res.json();

        pokemonsList.value = data["results"];
    }

    async function loadPokemon(name) {
        const URI = `https://pokeapi.co/api/v2/pokemon/${name}`

        const res = await fetch(URI);
        const data = await res.json();

        pokemonsLoadedNames.value.push(data["name"])
        pokemonsLoaded.value.push(data)
    }

    async function loadPokemons(offset, limit){
        // basic check for limits
        limit = limit > pokemonsListLength ? pokemonsListLength : limit;
        limit = limit < 0 ? 10 : limit

        // basic check for offset
        offset = offset < 0 ? 0 : offset;
        offset = offset > pokemonsListLength ? 0 : offset

        for (let i = offset; i < offset+limit; i++){

            // if the pokemon is already loaded skips the request for it
            if (pokemonsLoadedNames.value.includes(pokemonsList.value[i].name)) {
                continue;
            }

            // requests the pokemon given a name
            loadPokemon(pokemonsList.value[i].name)
        }
    }

    return {
        pokemonsList, 
        pokemonsLoaded, 
        pokemonsListLength, 
        
        pokemonsLoadedLength, 
        pokemonsLoadedNames, 
        
        getList,
        loadPokemon,
        loadPokemons
    }
})

我有以下组件,它利用该存储来获取口袋妖怪:

<template>
    <div class="pokedex">
        <PokemonImage class="pokemon-figure" pokemon="" />
        <ul v-if="pokemonsToShow" class="pokemon-showcase">
            <li class="pokemon-item" v-for="pokemon in pokemonsToShow">
                <PokemonCard :pokemon="pokemon" />
            </li>
        </ul>
        <div class="navigation">
            <button v-show="page !== 1" @click="pageChange(-1)">Previous Page</button>
            <button @click="pageChange(1)">Next Page</button>
        </div>
        {{ page }}
    </div>
</template>

<script setup>
import { onBeforeMount, ref, computed, watch } from 'vue';
import { usePokemonStore } from '../stores/pokemon'
import PokemonCard from '../components/PokemonCard.vue'
import PokemonImage from '../components/PokemonImage.vue'
const pokeStore = usePokemonStore();

const page = ref(1)

const pokemonsToShow = ref([])

// offset and limit calculate based on the page
const limit = computed(() => 20 );
const offset = computed(() => page.value * limit.value - limit.value);

// initial load
onBeforeMount(async () => {
    await pokeStore.getList()
    await pokeStore.loadPokemons(0, limit.value)
    pokemonsToShow.value = pokeStore.pokemonsLoaded.slice(0, pokeStore.pokemonsLoadedLength)
})

const pageChange = async (step) => {
    page.value = page.value + step
    await pokeStore.loadPokemons(offset.value, limit.value)

    const start = offset.value;
    const end = offset.value + limit.value;
    console.log(start, end)
    console.log(pokeStore.pokemonsLoaded)
    pokemonsToShow.value = pokeStore.pokemonsLoaded.slice(start, end)
    console.log(pokemonsToShow.value)
}
</script>

现在,当用户单击页面按钮时,page.value 会更新,因此偏移量和限制的计算值也会更新(实际上只有偏移量更新),如果页面是新的,我可以从中加载新的口袋妖怪我通过调用 pokeStore.loadPokemons(offset.value, limit.value) 函数并在 pageChange 函数中等待它来完成的。但是现在我想更改 pokemonsToShow,所以我想在存储中获取加载的 pokemons 数组的一部分,但每次我尝试对该数组进行切片时,我什么也得不到,即使当我使用 console.log(pokeStore.pokemonsLoaded) 打印数组时数组显示为使用新值更新,并且范围正确。

我希望数组能够正确切片,因为如果我在此函数调用中放置静态值:

    pokemonsToShow.value = pokeStore.pokemonsLoaded.slice(2, 4)
}

它出于某种原因起作用,但不适用于动态计算的值

【问题讨论】:

    标签: vue.js pinia


    【解决方案1】:

    这是关于console.log() 的一件棘手的事情。 console.log(pokeStore.pokemonsLoaded) 将向您显示获取数据的结果,即使 console.log 实际上是在获取完成之前执行的。这是因为许多浏览器显示对象数据的“实时”视图。

    https://developer.mozilla.org/en-US/docs/Web/API/Console/log#logging_objects

    不要使用console.log(obj),使用console.log(JSON.parse(JSON.stringify(obj))) ...许多浏览器提供实时视图,随着值的变化不断更新。这可能不是你想要的。

    那么很可能在您切片时数组实际上尚未更新。我也相信这是真的,因为即使您等待这个调用:await pokeStore.loadPokemons(...),该函数也不会等待它对 loadPokemon() 的调用。由于没有等待,该函数会在获取完成并返回到您的组件代码之前立即完成执行。

    我相信如果你确实等待那个电话,一切都应该开始工作

    async function loadPokemons(offset, limit){
      .
      .
      .
      await loadPokemon(pokemonsList.value[i].name)
    }
    

    【讨论】:

      猜你喜欢
      • 2014-01-25
      • 2012-01-25
      • 2021-04-24
      • 2023-04-07
      • 1970-01-01
      • 2023-01-12
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      相关资源
      最近更新 更多