Why the slice method doesn't work on array prop? - vue.js

I have the following code which defines a Pinia storage:
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
}
})
And I have the following component which makes use of that storage to get the pokemons:
<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>
Now when the user clicks on the page button the page.value is updated so that the computed values for the offset and the limit are also updated (in reality only the offset updates) that way if the page is new I can load new pokemons from that which I do by calling the pokeStore.loadPokemons(offset.value, limit.value) function and awaiting for that inside the pageChange function. But now I want to change the pokemonsToShow so I want to get a slice of the array of loaded pokemons in the storage but every time I try to slice that array I get back nothing, even though when I print the array using console.log(pokeStore.pokemonsLoaded) the array shows as updated with the new values, and the ranges are correct.
I'm expecting the array to slice correctly since if I put static values in this function call:
pokemonsToShow.value = pokeStore.pokemonsLoaded.slice(2, 4)
}
It works for some reason, but not with the values calculated dinamically

This is a tricky thing about console.log().
console.log(pokeStore.pokemonsLoaded) will show you the result of the fetched data even if console.log is in reality executed before the fetch is done. This is due to the fact that many browsers show a "live" view of object data.
https://developer.mozilla.org/en-US/docs/Web/API/Console/log#logging_objects
Don't use console.log(obj), use console.log(JSON.parse(JSON.stringify(obj))) ... many browsers provide a live view that constantly updates as values change. This may not be what you want.
It is probable then that the array has not actually been updated at the time you slice it. I also believe this is true because even though you await this call: await pokeStore.loadPokemons(...), that function does not await it's call to loadPokemon(). Since there is no await, the function immediately finishes executing before the fetch has finished and returns to your component code.
I believe if you do await that call, everything should start working
async function loadPokemons(offset, limit){
.
.
.
await loadPokemon(pokemonsList.value[i].name)
}

Related

React Native map "Undefined" is not a function

I'm trying to get data from API
but. I'm getting this error Error Image.
Here is my code.
const [datas, setDatas] = useState(" ");
const res = async () => {
const response = await axios.get("http://hasanadiguzel.com.tr/api/kurgetir");
setDatas(response.data.TCMB_AnlikKurBilgileri);
};
datas.map((item) => {
return (
<KurCard
title={item.Isim}
alis={item.BanknoteBuying}
satis={item.BanknoteSelling}
/>
);
});
How can I solve this?
I'm trying to map() datas, because I need it
Hi #n00b,
The data that datas is initially being set to an empty string, which does not have a map method. First, you need an empty array instead of an empty stringuseState([]). Now you can map.
const [datas, setDatas] = useState([]);
const res = async () => {
const response = await axios.get('http://hasanadiguzel.com.tr/api/kurgetir');
setDatas(response.data.TCMB_AnlikKurBilgileri);
};
{datas.length > 0 &&
datas.map((item) => {
return <KurCard title={item.Isim} alis={item.BanknoteBuying} satis={item.BanknoteSelling}/>
})
}
make sure you data. it has a length greater than 0 before trying to map over it.
Assuming your API request is valid, you would need to actually return something from the component itself and not just the array:
return datas.map((item) => {return <KurCard title={item.Isim} alis={item.BanknoteBuying} satis={item.BanknoteSelling}/>})

for loop only iterating twice with axios

const [Datalist,setDatalist] = useState([]);
useEffect(() => {
axios.get( 'http://0.0.0.0:8000/api/v1/questions/history/1')
.then(response => {
const questions = response.data;
const datalist = [];
for (let i = 0; i < questions.length - 1; i++) {
const data = new Object();
data.isExpanded = false;
data.question_id = questions[i].id;
data.question = questions[i].content;
data.type = questions[i].type;
data.commentType = questions[i].comment_type;
data.answer = [];
datalist.push(data);
}
setDatalist(datalist);
});
},[]);
I have three questions in my database currently. The for loop should be iterating through 0 to 2, however, it is only iterating twice.
And I'm also having problems putting the data into Datalist.
Anybody know where the issue is??
Thanks in advance!!
Change your for loop to this:
for (let i = 0; i < questions.length; i++)
Since you are iterating over each question you receive, you could use the map-method (if your environment supports ES6-Syntax - but since you're using react, it most likely dooes).
From the MDN Docs:
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
With map, your code could look like this:
(Also note the removal of const data = new Object();. you can initialize an object and assign its properties/values at the same time)
const [Datalist,setDatalist] = useState([]);
useEffect(() => {
axios.get( 'http://0.0.0.0:8000/api/v1/questions/history/1')
.then(response => {
const questions = response.data;
const datalist = questions.map(question => {
return {
isExpanded: false;
question_id: question.id;
question: question.content;
type: question.type;
commentType: question.comment_type;
answer: [];
};
});
setDatalist(datalist);
});
},[]);

tfjs-node memory leak even after proper tensor disposal

I've struggling to find where a memory leak occurs in this file. This file is exported as an Event Listener. For context, I have 92 shards (meaning 92 of these listeners) running. I import the model from outside of this file so it's only loaded once per shard occurrence (stable 75 tensors in memory). However, after a few minutes, all the RAM on my computer is consumed (the function inside the file is called a dozen or so times per second). Have I overlooked any place which may cause this memory leak?
const use = require(`#tensorflow-models/universal-sentence-encoder`);
const tf = require(`#tensorflow/tfjs-node`);
const run = async (input, model) => {
const useObj = await use.load();
const encodings = [ await useObj.tokenizer.encode(input) ];
const indicesArr = encodings.map(function (arr, i) { return arr.map(function (d, index) { return [i, index]; }); });
var flattenedIndicesArr = [];
for (i = 0; i < indicesArr.length; i++) {
flattenedIndicesArr = flattenedIndicesArr.concat(indicesArr[i]);
}
const indices = tf.tensor2d(flattenedIndicesArr, [flattenedIndicesArr.length, 2], 'int32')
const value = tf.tensor1d(tf.util.flatten([ encodings ]), 'int32')
const prediction = await model.executeAsync({ Placeholder_1: indices, Placeholder: value });
const classes = [ 'Identity Attack', 'Insult', 'Obscene', 'Severe Toxicity', 'Sexual Explicit', 'Threat', 'Toxicity' ]
let finArr = [];
let finMsg = `Input: ${input}, `;
for (i = 0; i < prediction.length; i++) {
const sorted = tf.topk(prediction[i], 2);
const predictions = [ sorted.values.arraySync(), sorted.indices.arraySync() ];
const percentage = (predictions[0][0][0]*100).toFixed(2);
if (predictions[1][0][0] == 1) {
finArr.push(`${classes[i]} (${percentage}%)`);
}
tf.dispose([ sorted, predictions ]);
}
for (i = 0; i < finArr.length; i++) {
finMsg+=`${finArr[i]}, `;
}
tf.dispose([ prediction, indices, value, useObj ]);
console.log(finMsg);
console.log(tf.memory());
};
const main = async (message, client, Discord, model) => {
if (message.author.bot) return;
const input = message.content;
await run(input, model);
};
module.exports = {
event: 'messageCreate',
run: async (message, client, Discord, model) => {
await main(message, client, Discord, model);
},
};
to start with, you say this runs multiple times - so why are you loading model again and again? and disposing model is tricky, big chance that's part of your memory leak.
move const useObj = await use.load() outside of run loop and don't dispose it until you're done with all of the runs.

getting undefined on fetching rss feed

I want to randomly display some of the news from a google rss news feed using the url and the package react-native-url-preview. Im doing a fetch call on it:
const [rssFeed, setRssFeed] = useState([]);
const [shouldFetch, setShouldFetch] = useState(true);
var feed = [];
if (shouldFetch) {
console.log("shouldFetch");
getFeed();
setShouldFetch(false);
}
function getFeed() {
console.log("getFeed: " + shouldFetch);
fetch(
"https://news.google.com/rss/search?q=cars&hl=en-GB&gl=GB&ceid=GB%3Aen"
)
.then((response) => response.text())
.then((responseData) => rssParser.parse(responseData))
.then((rss) => {
console.log(typeof rss.items);
let feedItems = rss.items;
feed = feedItems;
// #ts-ignore
setRssFeed(rss.items);
});
}
if (!shouldFetch) {
console.log(rssFeed);
var randomArr = [];
while (randomArr.length < 4) {
var r = Math.floor(Math.random() * 100);
if (randomArr.indexOf(r) === -1) randomArr.push(r);
// #ts-ignore
console.log(r + " " + rssFeed[r].links[0].url);
}
}
This only works sometimes!
50% of the times I get the error: undefined is not an object (evaluating 'rssFeed[r].links'.
I thought this is beacause of the reloading in react-native and this is why i put the if check. But it has not solved it. Any ideas?
You can use optional chaining like rss?.items.
which means if rss is present check for rss.item.
rssFeed?.[r]?.links
Sometimes you get an Undefined Error because the UI gets rendered before the actual data is present.

How to count the number of elements in this particular object

I am making a call to an API and the response is somehow what I expect. However, I want to count the number of elements returned and I can not do it. This is what I think is important from the code.
Call in Vue component
data(){
return {
messages: {}
}
},
loadMessages(){
axios.get("api/messagesmenu")
.then((data) => { this.messages = data.data})
}
Api controller
public function index(){
$messages = Message::all()->where('read_at', NULL);
if(isset($messages)){
foreach($messages as $message){
$from = User::find($message->from_id);
$message->fromPrenom = $from->first_name;
$message->fromNom = $from->last_name;
$message->fromImage = $from->user_image;
}
}else{
$messages = [];
}
return $messages;
}
Type of response from the API
{"3":{"id":560,"from_id":2,"to_id":1,"content":"tgr","created_at":"2019-07-15 16:59:03","read_at":null,"fromPrenom":"abdel1","fromNom":"Hidalgo","fromImage":"user2-160x160.png"}}
I want to count the number of objects I obtain. if (in vue component) I do
this.messages.length
it returns undefined
Try this:
const messages = {"3":{"id":560,"from_id":2,"to_id":1,"content":"tgr","created_at":"2019-07-15 16:59:03","read_at":null,"fromPrenom":"abdel1","fromNom":"Hidalgo","fromImage":"user2-160x160.png"}}
console.log(Object.keys(messages).length) // 1
Or in your code:
...
.then((data) => {
this.messages = data.data
console.log(Object.keys(this.messages).length)
})