I'm trying to make a tinder-like clone where I want to show each 5 seconds a different user photo, I first get array of only images from matches and then with setInterval which I finally got to work inside effect I loop through images array and change active index of image, however when I console log active image, it's always the same image...
This always returns same active Index and same active image
console.log(images[activeImageIndex]);
useEffect(() => {
getImagesArray(mapStore.blurredMatches);
const interval = setInterval(() => {
if(images.length>0)
{
flipAndNextImage();
}
}, 5000);
return () => clearInterval(interval);
}, []);
const getImagesArray = (users) =>
{
let copy = [];
for(var i=0;i<users.length;i++)
{
copy.push(users[i].images[0]);
}
setImages(copy);
console.log('Setting images array',images);
};
const flipAndNextImage= () =>
{
console.log(images,'images');
if(activeImageIndex == images.length-1)
{
setActiveImageIndex(0);
console.log(images[activeImageIndex]);
}
else
{
setActiveImageIndex(activeImageIndex+1);
console.log(images[activeImageIndex]);
}
};
I believe this is because you update your activeImageIndex before logging the state
Related
I am having a problem with sessionStorage; in particular, I want the id of the ads to be saved in the session where the user puts the like on that particular favorite article.
However, I note that the array of objects that is returned contains the ids starting with single quotes, as shown below:
['', '1', '7']
but I want '1' to be shown to me directly.
While if I go into the sessionStorage I notice that like is shown as:
,1,7
ie with the leading comma, but I want it to start with the number directly.
How can I fix this?
function likeAnnunci(){
let likeBtn = document.querySelectorAll('.like');
likeBtn.forEach(btn => {
btn.addEventListener('click', function(){
let id = btn.getAttribute('ann-id');
//sessionStorage.setItem('like', [])
let storage = sessionStorage.getItem('like').split(',');
//console.log(storage);
if(storage.includes(id)){
storage = storage.filter(id_a => id_a != id);
} else {
storage.push(id);
}
sessionStorage.setItem('like', storage)
console.log(sessionStorage.getItem('like').split(','));
btn.classList.toggle('fas');
btn.classList.toggle('far');
btn.classList.toggle('tx-main');
})
})
};
function setLike(id){
if(sessionStorage.getItem('like')){
let storage = sessionStorage.getItem('like').split(',');
if(storage.includes(id.toString())){
return `fas`
} else {
return `far`
}
} else {
sessionStorage.setItem('like', '');
return`far`;
}
}
The main issue you're having is that you're splitting on a , instead of using JSON.parse().
Also, you've got some other code issues and logical errors.
Solution:
function likeAnnunci() {
const likeBtn = document.querySelectorAll('.like');
likeBtn.forEach((btn) => {
btn.addEventListener('click', function () {
let id = btn.getAttribute('ann-id');
//sessionStorage.setItem('like', [])
let storage = JSON.parse(sessionStorage.getItem('like') || '[]');
//console.log(storage);
if (!storage.includes(id)) {
storage.push(id);
}
sessionStorage.setItem('like', JSON.stringify(storage));
console.log(JSON.parse(sessionStorage.getItem('like')));
btn.classList.toggle('fas');
btn.classList.toggle('far');
btn.classList.toggle('tx-main');
});
});
}
More modular and optimal solution:
const likeBtns = document.querySelectorAll('.like');
// If there is no previous array stored, initialize it as an empty array
const initLikesStore = () => {
if (!sessionStorage.getItem('likes')) sessionStorage.setItem('likes', JSON.stringify([]));
};
// Get the item from sessionStorage and parse it into an array
const grabLikesStore = () => JSON.parse(sessionStorage.getItem('likes'));
// Set a new value for the likesStore, automatically serializing the value into a string
const setLikesStore = (array) => sessionStorage.setItem('likes', JSON.stringify(array));
// Pass in a value.
const addToLikesStore = (value) => {
// Grab the current likes state
const pulled = grabStorage();
// If the value is already there, do nothing
if (pulled.includes(value)) return;
// Otherwise, add the value and set the new array
// of the likesStore
storage.push(value);
setLikesStore(pulled);
};
const likeAnnunci = (e) => {
// Grab the ID from the button clicked
const id = e.target.getAttribute('ann-id');
// Pass the ID to be handled by the logic in the
// function above.
addToLikesStore(id);
console.log(grabLikesStore());
btn.classList.toggle('fas');
btn.classList.toggle('far');
btn.classList.toggle('tx-main');
};
// When the dom content loads, initialize the likesStore and
// add all the button event listeners
window.addEventListener('DOMContentLoaded', () => {
initLikesStore();
likeBtns.forEach((btn) => btn.addEventListener('click', likeAnnunci));
});
I am trying to get the doc id of each data entry upon click to delete that specific record, but upon checking it is only showing id of the first entry made in the Firebase.
const deleteRecord = () => {
db.collection("records").onSnapshot((querySnapshot) => {
querySnapshot.forEach((doc) => {
// console.log(doc.id)
let recToDel = document.querySelectorAll(".records")
for (let toDelRecord of recToDel) {
toDelRecord.onclick = () => {
console.log(doc.id)
}
}
})
})
}
The loops are nested, so the last iteration of the querySnapshot.forEach loop is the one that sets the same doc.id for every recToDel dom element.
Fix by looping just one collection and indexing into the other...
let recToDel = Array.from(document.querySelectorAll(".records"));
querySnapshot.docs.forEach((doc, index) => {
if (index < recToDel.length) {
let toDelRecord = recToDel[index];
toDelRecord.onclick = () => {
console.log(doc.id)
}
}
});
If there are fewer .records elements than there are docs, some won't be assigned.
Doing this onSnapshot will cause these assignments to be made every time the collection changes, including on deletes. If that's not your intention, fix by changing to get().
I'm having this table view in React where I fetch an array from API and display it. When the user types something on the table search box, I'm trying to clear the current state array and render the completely new result. But for some reason, the result keeps getting appended to the current set of results.
Here's my code:
const Layout = () => {
var infiniteScrollTimeout = true;
const [apiList, setapiList] = useState([]);
//invoked from child.
const search = (searchParameter) => {
//Clearing the apiList to load new one but the console log after setApiList still logs the old list
setapiList([]); // tried setApiList([...[]]), copying the apiList to another var and emptying it and then setting it too.
console.log(apiList); //logs the old one.
loadApiResults(searchParameter);
};
let url =
AppConfig.api_url + (searchParameter || "");
const loadApiResults = async (searchParameter) => {
let response = await fetch(url + formurlencoded(requestObject), {
method: "get",
headers: headers,
});
let ApiResult = await response.json(); // read response body and parse as JSON
if (ApiResult.status == true) {
//Set the url for next fetch when user scrolls to bottom.
url = ApiResult.next_page_url + (searchParameter || "");
let data;
data = ApiResult.data;
setapiList([...data]);
}
}
useEffect(() => {
loadApiResults();
document.getElementById("myscroll").addEventListener("scroll", () => {
if (
document.getElementById("myscroll").scrollTop +
document.getElementById("myscroll").clientHeight >=
document.getElementById("myscroll").scrollHeight - 10
) {
if (infiniteScrollTimeout == true) {
console.log("END OF PAGE");
loadApiResults();
infiniteScrollTimeout = false;
setTimeout(() => {
infiniteScrollTimeout = true;
}, 1000);
}
}
});
}, []);
return (
<ContentContainer>
<Table
...
/>
</ContentContainer>
);
};
export default Layout;
What am I doing wrong?
UPDATE: I do see a brief moment of the state being reset, on calling the loadApiResult again after resetting the state. The old state comes back. If I remove the call to loadApiResult, the table render stays empty.
add apiList in array as the second parameter in useEffect
You need to use the dependencies feature in your useEffect function
const [searchParameter, setSearchParameter] = useState("");
... mode code ...
useEffect(() => {
loadApiResults();
... more code ...
}, [searchParameter]);
useEffect will automatically trigger whenever the value of searchParameter changes, assuming your input uses setSearchParameter on change
I am doing a time-to-click score table but first I have to localstorage each time I get in a game but I dont know how I have been trying everything but it still not working, I need to finish this fast, and I need help... otherwise I would try everyday to resolve this alone because I know that's the way to learn.. When I press the finished button It says that times.push() is not a function.
let times = Array.from(
{ length: 3 }
)
let interval2;
// Timer CountUp
const timerCountUp = () => {
let times = 0;
let current = times;
interval2 = setInterval(() => {
times = current++
saveTimes(times)
return times
},1000);
}
// Saves the times to localStorage
const saveTimes = (times) => {
localStorage.setItem('times', JSON.stringify(times))
}
// Read existing notes from localStorage
const getSavedNotes = () => {
const timesJSON = localStorage.getItem('times')
try {
return timesJSON ? JSON.parse(timesJSON) : []
} catch (e) {
return []
}
}
//Button which starts the countUp
start.addEventListener('click', () => {
timerCountUp();
})
// Button which stops the countUp
document.querySelector('#start_button').addEventListener('click', (e) => {
console.log('click');
times = getSavedNotes()
times.push({
score: interval2
})
if (interval) {
clearInterval(interval);
clearInterval(interval2);
}
})
You probably need to change the line times = JSON.parse(localStorage.times || []) to times = JSON.parse(localStorage.times) || [] this makes sure that if the parsing fails it will still be an array.
Even better is wrap them with try-catch just in case if your JSON string is corrupted and check if the time is an array in the finally if not set it to empty array.
I want to be able to click on a certain element and then remove it from the player1 array and place it into the playCard array. Currently this is attached to a button on the page.
choseCard = () => {
this.setState(({
playCard,
player1
}) => {
return {
playCard: [...playCard, ...player1.slice(0, 1)],
player1: [...player1.slice(1, player1.length)]
};
});
}
Currently this takes the first item from the player1 array and places it in the playCard array. I want to be able to select a certain element(card) from the player array instead of just taking the first element. I'm having a hard time thinking of the way to do this in react as I am still a beginner.
Is there a way to maybe move the selected card to the first element then use the above code?
try passing the index of element you are clicking on to the function, this might possibly work...
choseCard = (index) => {
this.setState(({playCard, player1}) =>
{
return
{
playCard: [...playCard, ...player1.slice(index, 1)],
player1: [...player1.slice(0, index),...player1.slice(index,player1.length)]
};
});
}
You can insert whatever logic you need right above the return statement, then return the results:
choseCard = () => {
this.setState(({playCard, player1}) => {
// change `index` to whichever index you want to remove
const index = 1;
const toInsert = player1[index];
const player1Copy = player1.slice();
player1Copy.splice(index, 1);
const playCardCopy = playCard.slice();
playCardCopy.push(toInsert);
return {
playCard: playCardCopy,
player1: player1Copy,
};
});
}
you could pass the card object in the choseCard function
choseCard(card) => {
const {playCard, player1} = this.state;
return this.setState({
playCard: playCard.concat(card),
player1: player1.filter(c => c.id !== card.id)
});
}
this is also under the assumption that each card has a unique identifier.