changing state before next keydown in react - reactjs

I am creating a game that when your health goes below 0, on a keydown it prints in a div:
"Game_over_:(_click_to_continue" letter by letter. I was getting a bug where the letters would print out multiple times like ggggaaammmeee ooovvveerr.
I set up a conditional statement where if the state gameOver is 0 and after a keydown event, then it activates the setInterval, else it does not. That solved the problem to some extent, however, the state sometimes changes a second late, and after setting up console.log(this.state.gameOver), it sometimes prints 0 twice before this.state.gameOver actually changes to 1. Other times it works just fine.
if (this.state.gameOver===0){
console.log(this.state.gameOver)
var s1="Game_Over\n:(\nClick_to_continue..."
var v1 =0
var b = document.getElementById("redButton")
var arr1 = setInterval(function(){
if(v1===0){b.innerText=""};b.innerText= b.innerText+s1[v1];v1+=1;
if(v1==s1.length){clearInterval(arr1)}}, 100)
this.setState({gameOver:1})
}
It's still sometimes printing Ggaammee Ovveerr.

So all I had to do was set up a conditional statement that depends on whether a variable is true or false. Once the setInterval function is triggered, the variable changes to false so that more keydowns wont cause multiple calls to setInterval.
var check;
if (check!==false){
check=false;
var arr1 = setInterval(function(){
if(v1===0){b.innerText=""};
b.innerText= b.innerText+s1[v1];v1+=1;
if(v1==s1.length){clearInterval(arr1)}}, 100)}
Once I click the screen with the mouse:
check=true;

Related

setState in while loop causing "Too many re-renders. React limits the number of renders to prevent an infinite loop"

I am trying to calculate countDiff and add the object to the record array countDiff times. For example, if countDiff value is two then I would like to add two same objects with incremented tempRecordId.
However "Too many re-renders. React limits the number of renders to prevent an infinite loop" error came up. Do you know any way to setState in a loop or the way to figure out this logic?
const countDiff = homeRecordCount - awayRecordCount;
let i = 0;
let insertTeamId = countDiff > 0 ? awayTeamId : homeTeamId;
if (countDiff != 0)
{
while(countDiff != i)
{
setTempRecordId(tempRecordId + 1);
addRowToRecord({scoreMemberName:null, scoreMemberId: null, scoreTeamId: insertTeamId, assistMemberName: null, assistMemberId: null, matchId: matchId, codeId: 7, id: 0, tempRecordId: tempRecordId })
i++;
}
}
You shouldn't use conditionals nor loops in your Hook component. https://reactjs.org/docs/hooks-rules.html
In this case you could just add all the records at once.
The best way to handle this situation is to construct the final object you need before you ever set state in the first place ie move your set state to after the while loop.
It means once you call to setState then it will render your page. your logic set to never ending loop . I guess All the time (countDiff != i = > true)comes to inside of the while loop. Please set your logic with some ending condition.

Target input field in document and set & remove a class name if input field has any value

I have a bunch of input fields into which I'd like to set a someClass name only in condition if an input field has some value. Remove someClass name if it doesn't.
I'm currently studying manipulating forms and forms fields using JavaScript and this is the code I'm working on.
// Add a class to an element, without removing/affecting existing values
var inputs = document.getElementsByTagName('input');
for (var i = 0; i < inputs.length; i++) {
// Set HTML elements collection index?
var input = inputs[i];
input.addEventListener('input', function() {
if (input.value.length > 0 && !input.className.match(/(?:^|\s)someClass(?!\S)/)) {
console.log("Input has some value");
input.className += "someClass";
}
if (input.value.length == 0) {
console.log("Input is empty");
input.className = input.className.replace( /(?:^|\s)someClass(?!\S)/g , '' );
}
});
}
The current code do what it suppose to do only on last input field. It occurred to me that var input is overwritten every time there is a new loop.
So I was thinking to target current element by some conditional statement within the loop. I can't think of anything else (with little knowledge I have about this) except manually assigning some of input's attributes.
The issue you are running into is that each input event listener is updating w/e element the variable input is representing at the time the event is fired, and is therefore only updating that element.
So the timeline goes like this:
Add event listener to input 1 | input = input1
Add Event Listener to input 2 | input = input2
Add event listener to input 3 | input = input3
All 3 event listeners are going to change the element held by variable input, which at this time is only input3.
User clicks inside input and types
var input which is input3 gets updated
As Sean pointed out, you need each eventListener function to update the specific element that fired that event. Here you have 3 options:
Use this this keyword
https://jsfiddle.net/5gbnykme/1/
Use event.target as reference
https://jsfiddle.net/5gbnykme/2/
Use a wrapper function to scope your variable locally
https://jsfiddle.net/5gbnykme/3/
TL;DR Make sure the element called in your event listener is the element that triggered the event.

AngularJS' $interval.cancel not working

As stated in the title,
every time I try to use $interval.cancel to cancel an existing interval, it doesn't work.
window.recordedAudio = undefined;
var isRecordingComplete = $interval(function(){
console.log(window.recordedAudio);
if (window.recordedAudio!=undefined) $timeout.cancel(isRecordingComplete);
},100);
$timeout(function(){
window.recordedAudio = "abc";
},2000);
In fact, when window.recordedAudio!= undefined (window.recordedAudio is set to "abc" after 2000ms), the $interval keeps looping and at the same time the
console.log(window.recordedAudio)
keeps being printed (+- 10 times undefined and finally abc but it keeps printing abc rather than just stop).
You are mixing $interval and $timeout.cancel.

AngularJS : Why the data is not displayed in view may I use $scope.apply?

I am getting data from service and display on view using ng-repeat .Actually I am getting event when user scroll to bottom mean when user reached to bottom I will do something.When It reached to bottom I am changing the contend of my array .I am getting the correct contend in ng-repeat array (display array) but it is not reflect on view why ? May I use $scope.apply() or $scope.digest()
Here is my code
http://plnkr.co/edit/XgOxJnPXZk4DneJonlKV?p=preview
Here I am changing the contend of my display array which is not reflect on view
if (container[0].offsetHeight + container[0].scrollTop >= container[0].scrollHeight) {
if(scope.var<scope.arrays.length)
scope.display=[];
var nextvar =++counter;
var increment=counter+1
console.log("nextvar:"+nextvar+"increment:"+increment)
scope.display=scope.arrays[nextvar].concat(scope.arrays[increment]);
console.log(scope.display)
}
As #Claies mentioned you should use apply(). Though the digest() would probably have worked as well.apply() calls digest() internally. He also mentioned that your variable that seems to be storing the page number gets reset to 0 each time you scroll. You should store that in a scope variable outside that handler.
I tried to fix with minimum change
http://plnkr.co/edit/izV3Dd7raviCt4j7C8wu?p=preview
.directive("scrollable", function() {
return function(scope, element, attrs) {
var container = angular.element(element);
container.bind("scroll", function(evt) {
console.log('scroll called'+container[0].scrollTop);
var counter = scope.page;
if (container[0].scrollTop <= 0) {
if (scope.var > 0)
scope.display = scope.arrays[--scope.var].concat(scope.arrays[scope.var+1]);
}
if (container[0].offsetHeight + container[0].scrollTop >= container[0].scrollHeight) {
if (scope.var < scope.arrays.length)
scope.display = [];
var nextvar = ++counter;
var increment = counter + 1
console.log("nextvar:" + nextvar + "increment:" + increment)
scope.display = scope.arrays[nextvar].concat(scope.arrays[increment]);
console.log(scope.display)
scope.page = counter;
}
scope.$apply();
});
};
})
generally I would have implemented this differently. For example by having a spinning wheel on the bottom of the list that when displayed you get the rest of data.
It is difficult to give you a full working plunker. Probably you should have multiple JSON files in the plunker, each containing the data for one page so that we can add the data to the bottom of the display list.
After you modify display array you just have to call scope.$apply() so that it runs the $digest cycle and updates the view. Also you need the initialize scope.var either in your controller or the directive and modify it conditionally.
I dont if this is what you want. I have modified the plunker take a look.
http://plnkr.co/edit/J89VDMQGIXvFnK86JUxx?p=preview

Sometime scope variable not getting set

This seems pretty strange to me but I hope there's someone that has come across this before and point me in the right direction.
I have a variable being set in scope within an $interval and the value is sometimes "sticking" and sometimes not.
someInterval = $interval(function() {
SomeFactory.getsomething($scope.highestnumber)
.then(function(response) {
if (response.number > $scope.highestnumber)
$scope.highestnumber = response.number;
});
}, 30000);
Most of the time this works - $scope.highestnumber is set with the updated value and 30 seconds later getSomething() is called passing the updated value.
However, every now and then (and I wish I could duplicate on demand), $scope.highestnumber is set with a new value but getSomething() is called with the value it had before the update executed. I have verified it by catching the value of $scope.highestnumber after it's been set to the new value, and then checking what's being passed into getSomething() on the next cycle.
So the sequence would be...
$scope.highestnumber = 10
getsomething(10) called
returns response.number = 11
$scope.highestnumber set to 11 (verified)
getSomething(10) called 30 seconds later

Resources