ReactJS - timeouts not completeing, set within loop - javascript

I'm working with the below code to trigger a flash when fields change. All is well, except that my timeouts are not actually completing due to some javascript magic i do not understand. If anyone can shed light on why these timeouts would not be completing that would be very helpful - thanks!
I'm assuming it has something to do with using this inside of the loop?
componentDidUpdate(prevProps) {
const updates = {};
fields(this.props).forEach(f => {
if (!_.isEqual(this.props[f], prevProps[f])) {
updates[updatedKey(f)] = true;
}
});
if (Object.keys(updates).length > 0) {
this.setState({ ...updates });
Object.keys(updates).forEach(f => {
const tkey = timeoutKey(f);
clearTimeout(this[tkey]);
this[tkey] = setTimeout(() => this.setState({ [updatedKey(f)]: false }), 700);
});
}
}

Related

JavaScript pause sound if false

I have an async function that gets an array of objects, I set a soundOn to true if:
soundOn = content.some(ele => ele.order_status === 'processing');
It works partly, e.g. plays sound when above is true - however continues to play even if soundOn evaluates to false. Here's the rest of my code.
function getOrders()
{
(async () => {
bgSound = new Audio("assets/sounds/spn.mp3");
soundOn = "";
const resp = await fetch(url+'/app/v1/post', {
//truncated
});
const content = await resp.json();
if(content.length > 0)
{
soundOn = content.some(ele => ele.order_status === 'processing');
}
(soundOn) ? setInterval(function () { bgSound.play() }, 5000) : bgSound.pause();
})();
setTimeout(getOrders, 30000);
}
content array looks like this (part of it).
[{"id":"1","order_status":"acknowledged", "type":"off"},
{"id":"1","order_status":"processing", "type":"off"},{"id":"1","order_status":"processing", "type":"off"}]
while the app is running those statuses get updated to acknowledged but the sound continues to play. I am not sure why this is the case, any help would be appreciated.
Adding a condition might help:
(soundOn) ? setInterval(function () { if (soundOn) bgSound.play() }, 5000) : bgSound.pause();

Autodesk Forge: Viewer Extension cant use .getExternalIdMapping()

class IBSProgressExtension extends Autodesk.Viewing.Extension{
constructor(viewer, options) {
super(viewer, options);
}
load() {
//For proof of concept project, I will simply store the externalIds here in a variable.
const allExternalIds = [
'8a00f4c7-0709-4749-88b6-abb0ddccf965-0006879a',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-000688ee',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068961',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068963',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a78',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a0d',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a0f',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a11',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a13',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068c2f',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068c31',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068c33',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b2e',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b30',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b32',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b34',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b3e',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b36',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b38',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b3a',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b3c'
];
this.viewer.model.getExternalIdMapping(data => onSuccessMapping(data));
function onSuccessMapping(data) {
const resArray = [];
allExternalIds.forEach(externalId => {
if (data[externalId]) resArray.push(data[externalId], externalId);
});
console.log(resArray);
};
console.log('IBSProgressExtension is loaded.');
return true;
}
};
Autodesk.Viewing.theExtensionManager.registerExtension("IBSProgressExtension", IBSProgressExtension);
Please have a look at my extension and please help me figure out why is this happening.
Every time i run it, the devtools logs: ViewerExtension.js:31 Uncaught TypeError: Cannot read properties of undefined (reading 'getExternalIdMapping').
The extensions get loaded before the model so the getExternalIdMapping() method does not have the model properties yet. To handle this scenario, we usually recommend using the viewer events such as Autodesk.Viewing.GEOMETRY_LOADED_EVENT to “catch” the moment when the model is available. It’s better to wait for the event. This will be fired when the model/drawing finishes loading.
Instead of:
this.viewer.model.getExternalIdMapping(data => onSuccessMapping(data));
Try this:
this.viewer.addEventListener(Autodesk.Viewing.GEOMETRY_LOADED_EVENT, (x) => {
this.viewer.model.getExternalIdMapping(data => onSuccessMapping(data));
});
Please test this and see if it's helpful. I tried to incorporate items from your comments to help you structure it out.
class IBSProgressExtension extends Autodesk.Viewing.Extension {
constructor(viewer, options) {
super(viewer, options);
this._externalIds = null;
//Eventually will want to pass in your external IDs to this function, I assume:
//this._externalIds = options.externalIds
this._doStuff = () => {
this.startDoingStuff();
};
}
load() {
console.log("loading extension");
//For now, hard coded like your example.
this._externalIds = [
"8a00f4c7-0709-4749-88b6-abb0ddccf965-0006879a",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-000688ee",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068961",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068963",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a78",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a0d",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a0f",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a11",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a13",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068c2f",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068c31",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068c33",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b2e",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b30",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b32",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b34",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b3e",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b36",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b38",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b3a",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b3c",
];
//Not sure if this is truly the right event, but it worked when I tested on mine.
this.viewer.addEventListener(Autodesk.Viewing.MODEL_LAYERS_LOADED_EVENT, this._doStuff);
}
startDoingStuff() {
console.log("startDoingStuff executing");
this.getDbIds(this._externalIds).then((CombinedArray) => {
this.setCustomColors(CombinedArray);
});
}
setCustomColors(arrayOfIDs) {
console.log("setCustomColors executing");
var somecolor = "#7D5B51";
var threecolor = new THREE.Color(somecolor);
var vectcolor = new THREE.Vector4(threecolor.r, threecolor.g, threecolor.b, 1);
arrayOfIDs.forEach((e) => {
this.viewer.setThemingColor(e[0], vectcolor, this.viewer.getVisibleModels()[0]);
});
}
getDbIds(externalIds) {
console.log("getDbIds executing");
return new Promise((resolve) => {
this.viewer.model.getExternalIdMapping((d) => {
//console.log("getDbIdFromExternalId Executed");
let responseArr = [];
externalIds.forEach((externalId) => {
if (d[externalId]) responseArr.push([d[externalId], externalId]);
});
console.log("resolving", responseArr);
resolve(responseArr);
});
});
}
}
Autodesk.Viewing.theExtensionManager.registerExtension("IBSProgressExtension", IBSProgressExtension);
Regarding this, I was trying to achieve 3 things at this stage.
Get the externalIds from Mongodb.
Compare the externalIds with the ones gotten from getExternalIdMapping().
Get DbIds of those that matched.
Solved these by realising 2 and 3 can be put inside a.then() after .loadDocumentNode().

Infinite for loop in useEffect when i want to check if a property of window object is here

I want to check on load if the object window has the property VL.refCode.
I use viral loops for my website and viral loop put in window.VL object the property refCode when a user is registered.
I put a for loop in a useEffect to check if this property exists or not, but unfortunately it becomes an infinite loop.
useEffect(() => {
if(window.VL){
if(window.VL.refCode){
setCryptoButtonMessage(t('common:cryptoButton_already_register'))
console.log('useEffect :user already register')
}
else{
console.log('useEffect : window.vl.refcode not exist')
}
}
else {
setCryptoButtonMessage(t('common:cryptoButton_title_waitlist'))
}
// t is for translation with i18n
},[t]);
This solution doesn't work because viral loop create window.VL object 1 to 2sec max after the first render.
If I put a setTimeout it's not a valid solution for users with mobile device / slow 3g / without fiber
So i use this solution
useEffect(() => {
let animation;
const check = () => {
console.log('je suis dans check');
console.log('je suis dans for');
if ((Object.prototype.hasOwnProperty.call(window.VL, 'refCode'))) {
console.log('je trouve refCode ');
setCryptoButtonMessage(t('common:cryptoButton_already_register'))
cancelAnimationFrame(animation);
return;
}
animation = requestAnimationFrame(check);
};
animation = requestAnimationFrame(check);
},[t]);
But this solution will never stop until window.VL.refCode exist ... not really best solution for website performance ...
I try to put a " simulate timer " but it becomes an infinite loop ...
useEffect(() => {
for (let i = 1; i < 10000; i += 1) {
let animation;
const check = () => {
if ((Object.prototype.hasOwnProperty.call(window.VL, 'refCode'))) {
setCryptoButtonMessage(t('common:cryptoButton_already_register'))
cancelAnimationFrame(animation);
return;
}
animation = requestAnimationFrame(check);
};
animation = requestAnimationFrame(check);
}
},[t]);
I don't know of any way of being automatically told when an object gets created on the window - so as far as I know the only way to do this is with a poll. If it was me, I'd abstract the logic for polling for the ref code into a new hook:
import { useEffect, useRef, useState } from 'react';
const useRefCode = (pollTimeMillis = 1000) => {
const timeoutRef = useRef(undefined);
const [refCode, setRefCode] = useState(window.VL?.refCode);
const cancelTimeout = () => {
if (!timeoutRef.current) return;
clearTimeout(timeoutRef.current);
timeoutRef.current = undefined;
};
useEffect(() => {
if (refCode) return;
setTimeout(() =>
setRefCode(window.VL?.refCode || undefined),
pollTimeMillis
);
return cancelTimeout;
}, [refCode]);
return refCode;
}
Then your other component that wants to change the message based on the ref code becomes very simple:
const OtherComponent = () => {
const refCode = useRefCode();
const translationKey = refCode
? 'common:cryptoButton_already_register'
: 'common:cryptoButton_title_waitlist';
return (
<div>{t(translationKey)}</div>
);
}

unable to change image source in DOM javascript

I’m Rahul and I’m new to coding. I have a query related to DOM event. Please look at the following code snippet -
let door1 = document.getElementById('one');
door1.src = "closed_door.svg";
const isClicked = (door) => {
if(door.src === "closed_door.svg") {
return true;
}
else {
return false;
}
};
door1.onclick = () => {
if(isClicked(door1)) {
door1.src = "beach.svg";}
};
To give you brief, one is an id for an element. Without isClicked, I am able to successfully change the src from closed door to beach on clicking. But when I introduce isClick, it doesn’t change. Can someone please tell me what I’m missing. I’ll be very thankful
Note - I'm building game similar to this - https://s3.amazonaws.com/codecademy-content/projects/chore-door/chore-door-final/index.html They are using the same process as mine. So please suggest a solution that tells me about the error I'm making here rather than an alternative to the problem
Regards
Rahul
As reported here:
the src reflected property will be the resolved URL — that is, the absolute URL that that turns into. So if that were on the page http://www.example.com, document.getElementById("foo").src would give you "http://www.example.com/images/example.png".
so to get the real src attribute you should use .getAttribute('src') like so:
const isClicked = (door) => {
if(door.getAttribute('src') === "closed_door.svg") {
return true;
}
else {
return false;
}
};
Ans also BTW, you can just shortcut it to:
const isClicked = (door) => door.getAttribute('src') === "closed_door.svg";
Replace your code with this..
let door1 = document.getElementById('one');
door1.src = "https://s3.amazonaws.com/codecademy-content/projects/chore-door/images/closed_door.svg";
const isClicked = (door1) => {
if(door1.src === "https://s3.amazonaws.com/codecademy-content/projects/chore-door/images/closed_door.svg") {
return true;
}
else {
return false;
}
};
door1.onclick = () => {
if(isClicked(door1)) {
door1.src = "https://s3.amazonaws.com/codecademy-content/projects/chore-door/images/beach.svg";}
};

What am I doing bad with localStorage?

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.

Categories

Resources