I need to assign to a reactive object a object from a reactive array inside script setup composition API, any suggestion?
Here is my code - the variable pokemonsReactiveArr
is:
export let pokemonsReactiveArr = ref<IPokemon[]>([]);
This array after the await call it contains 4 pokemons:
<script setup lang="ts">
import { onMounted, ref } from "vue";
import PokemonPicture from "../components/PokemonPicture.vue";
import PokemonsOptions from "../components/PokemonsOptions.vue";
import { getPokemonsOptions } from "../helpers/getPokemonOptions";
import { pokemonsReactiveArr } from "../helpers/getPokemonOptions";
let pokemons = ref<any[]>([]);
let selectedPokemon = ref<any>({});
let idPokemon = ref<number>(0);
defineExpose({ selectedPokemon });
onMounted(async () => {
console.log(
"array antes de llamar al helper de pokemons en Home view: ",
pokemonsReactiveArr
);
await getPokemonsOptions();
const rndInt = Math.floor(Math.random() * 4);
idPokemon.value = rndInt;
console.log(
"array despues del llamar al helper de pokemons en Home view: ",
pokemonsReactiveArr
);
console.log('el pokemon seleccionado es:',pokemonsReactiveArr.value[rndInt])
console.log("pokemon seleccionado antes: ", selectedPokemon.value);
selectedPokemon.value = pokemonsReactiveArr.value[rndInt];
console.log("pokemon seleccionado despues: ", selectedPokemon.value);
console.log("id del pokemon despues de la asignacion: ", idPokemon.value);
});
</script>
<template>
<v-container>
<v-row justify="center">
<!--
<h1 v-if="!selectedPokemon">Cargando pokemon...</h1>
-->
<div>
<PokemonPicture :pokemonId="idPokemon" :show="true" />
</div>
</v-row>
<v-row v-if="pokemons" justify="center">
<PokemonsOptions :pokemons="pokemonsReactiveArr" />
</v-row>
</v-container>
</template>
When I print in console the selected Pokemon it shows a empty proxy object but after assignment is undefined, how can I achieve the desired effect? Here I share the logic to get the array of pokemons:
import { ref } from "vue";
import pokemonAPI from "../api/pokemonApi";
import { IPokemon } from "../interface/IPokemon";
export let pokemonsReactiveArr = ref<IPokemon[]>([]);
const getPokemons = () => {
const pokemonsArr = Array.from(Array(650));
return pokemonsArr.map((_, index) => index + 1);
};
export const getPokemonsOptions = async () => {
const mixPokemons = getPokemons().sort(() => Math.random() - 0.5);
await getPokemonsName(mixPokemons.splice(0, 4));
};
const getPokemonsName = async (pokemonsArr: number[]) => {
pokemonsArr.forEach(async (pokemonID: number) => {
const response = await pokemonAPI.get(`/${pokemonID}`);
pokemonsReactiveArr.value.push({ name: response.data.name, id: response.data.id });
});
};
At the end I managed to get the behavior that I wanted through this code:
import { ref } from "vue";
import pokemonAPI from "../api/pokemonApi";
import { IPokemon } from "../interface/IPokemon";
export let pokemonsReactiveArr = ref<IPokemon[]>([]);
export let pokemonSelected = ref<IPokemon>({ id: 0, name: "" });
const getPokemons = () => {
const pokemonsArr = Array.from(Array(650));
return pokemonsArr.map((_, index) => index + 1);
};
export const getPokemonsOptions = async () => {
const mixPokemons = getPokemons().sort(() => Math.random() - 0.5);
await getPokemonsName(mixPokemons.splice(0, 4));
};
const getPokemonsName = async (pokemonsArr: number[]) => {
pokemonsArr.forEach(async (pokemonID: number) => {
const response = await pokemonAPI.get(`/${pokemonID}`);
if (pokemonsReactiveArr.value.length == 4) {
} else {
pokemonsReactiveArr.value.push({
name: response.data.name,
id: response.data.id,
});
if (pokemonsReactiveArr.value.length == 4) {
pokemonSelected.value =
pokemonsReactiveArr.value[Math.floor(Math.random() * 4)];
}
}
});
};
And in the HomewView.vue:
<script setup lang="ts">
import { onMounted, ref } from "vue";
import PokemonPicture from "../components/PokemonPicture.vue";
import PokemonsOptions from "../components/PokemonsOptions.vue";
import { getPokemonsOptions } from "../helpers/getPokemonOptions";
import {
pokemonsReactiveArr,
pokemonSelected,
} from "../helpers/getPokemonOptions";
import { IPokemon } from "../interface/IPokemon";
import { useGeneralStore } from "../stores/GeneralStore.ts";
const store = useGeneralStore();
let showDialog = ref<boolean>();
let answerMessage = ref<string>();
let showVictory = ref<boolean>(false);
let done = ref<boolean>(false);
onMounted(async () => {
await getPokemonsOptions();
});
async function checkRespuesta(pokemonClicked: IPokemon) {
if (pokemonSelected.value === pokemonClicked) {
store.acierto();
answerMessage.value = "¡Has acertado!";
showDialog.value = true;
showVictory.value = true;
done.value = true;
} else {
store.reiniciaJuego();
answerMessage.value = "¡Has fallado!";
showDialog.value = true;
showVictory.value = false;
done.value = true;
}
}
function cerrar() {
showDialog.value = false;
}
async function reiniciar() {
pokemonsReactiveArr.value = [];
pokemonSelected.value = { id: 0, name: "" };
showVictory.value = false;
done.value = false;
await getPokemonsOptions();
}
</script>
<template>
<v-container>
<template v-if="done">
<v-row justify="center">
{{ answerMessage?.toLocaleUpperCase() }}
</v-row>
<v-row justify="center">
<v-col cols="6">
<v-text-field
v-if="showVictory"
color="black"
single-line
variant="solo-filled"
readonly
>
<h2>{{ pokemonSelected.name }}</h2>
</v-text-field>
</v-col>
<PokemonPicture :pokemonId="pokemonSelected.id" :show="showVictory" />
</v-row>
<v-row justify="center">
<v-btn @click="reiniciar">Reiniciar</v-btn>
</v-row>
</template>
<template v-else>
<v-row justify="center">
<h1 v-if="!pokemonSelected">Cargando pokemon...</h1>
<div v-else>
<div v-if="pokemonSelected.id != 0">
<h1>¿Quién es este pokemon?</h1>
<PokemonPicture
:pokemonId="pokemonSelected.id"
:show="showVictory"
/>
</div>
</div>
</v-row>
<v-row justify="center">
<PokemonsOptions
:pokemons="pokemonsReactiveArr"
@pokemonmClickado="checkRespuesta($event)"
/>
</v-row>
</template>
<v-dialog v-model="showDialog" persistent width="auto">
<v-card>
<v-card-title>
{{ answerMessage }}
</v-card-title>
<v-card-subtitle> tienes {{ store.getPoints }} punto/s </v-card-subtitle>
<v-card-actions>
<v-row justify="center">
<v-btn @click="cerrar">OK</v-btn>
</v-row>
</v-card-actions>
</v-card>
</v-dialog>
</v-container>
</template>
I hope this'd be util for someone