SetInterval and clearInterval in ReactJS - reactjs

This was asked upon searching here, but the solutions were not working, or I have missed something.
This is the snippet of the code
tick(rev_new_arr) {
if(rev_new_arr.length > 0){
this.setState({
sim_play_date : rev_new_arr[0]
},()=>{
rev_new_arr.shift()
})
}else{
this.stopPlay()
}
}
playMap(){
const startDate = this.state.simulation_date;
const sim_dates = this.state.sim_dates;
const index_simdate = parseInt(sim_dates.indexOf(startDate) + 1, 0);
const new_arr = sim_dates.slice(0,index_simdate);
const rev_new_arr = new_arr.reverse();
this.timerID = setInterval(()=> this.tick(rev_new_arr), 1000);
}
stopPlay(){
console.log(this.timerID);
clearInterval(this.timerID);
}
setInterval works but when adding the function stopPlay() on click event in a button, it does not stop and still calls the tick function.
EDIT: I tried logging the timerID in console..It outputs 2 ids. I think that is the reason, why it's not stopping even calling clearInterval. What must be the reason of this?

Are your methods playMap() stopPlay() and tick() bound to the class? If not, try defining them like:
stopPlay = () => {
...
}

clearInterval is referring to global context,so bind it.
stopPlay(){
console.log(this.timerID);
clearInterval(this.timerID).bind(this);
}

Related

State variables not setting correctly, giving wrong results in 'if' condition

I'm setting some state variables in a ReactJS function based on the inputs received onClick. I'm adding these to a running total, and when that total exceeds a given pre-defined level, I want to set a flag. This flag would help me do a few things subsequently, inside the function and outside of it.
The problem I'm facing is that the 'if' is not evaluating correctly, though running totals are calculating fine. I can see them on a rendered element in a div, though on console.log I see the values from the previous time the function was executed onClick.
Because of this, the flag is not getting set correctly, which is causing me much chagrin.
Would deeply appreciate help, since I'm new to the new-age programming (I'm from the dinosaur era of 3rd generation programming).
Copying the relevant piece of code below..
const [assessCourseList, setAssessCourseList] = useState([]);
const [flag1, setFlag1] = useState(false)
const [totqns, setTotqns] = useState(0.0);
const [totmarks, setTotmarks] = useState(0.0);
function createAssessCourse1(e) {
e.preventDefault();
setTotqns(prev => { return (prev + Number(assessCourse.AC_CO_NoOfQns)) })
setTotmarks(prev => { return (prev + Number(assessCourse.AC_CO_TotMarks)) })
if (Number(totqns) >= Number(assessTotQns) || Number(totmarks) >= Number(assessTotMarks)) {
setFlag1(true);
} else {
setFlag1(false);
}
if (!flag1) {
setAssessCourseList(prev => {
return [...prev, assessCourse]
})
}
else {
return
}
}

Cypress while loop [duplicate]

I have 15 buttons on a page. I need to test each button.
I tried a simple for loop, like
for (var i = 1; i < 15; i++) {
cy.get("[=buttonid=" + i + "]").click()
}
But Cypress didn't like this. How would I write for loops in Cypress?
To force an arbitrary loop, I create an array with the indices I want, and then call cy.wrap
var genArr = Array.from({length:15},(v,k)=>k+1)
cy.wrap(genArr).each((index) => {
cy.get("#button-" + index).click()
})
Lodash is bundled with Cypress and methods are used with Cypress._ prefix.
For this instance, you'll be using the _.times. So your code will look something like this:
Cypress._.times(15, (k) => {
cy.get("[=buttonid=" + k + "]").click()
})
You can achieve something similar to a "for loop" by using recursion.
I just posted a solution here: How to use a while loop in cypress? The control of is NOT entering the loop when running this spec file? The way I am polling the task is correct?
Add this to your custom commands:
Cypress.Commands.add('recursionLoop', {times: 'optional'}, function (fn, times) {
if (typeof times === 'undefined') {
times = 0;
}
cy.then(() => {
const result = fn(++times);
if (result !== false) {
cy.recursionLoop(fn, times);
}
});
});
Then you can use it by creating a function that returns false when you want to stop iterating.
cy.recursionLoop(times => {
cy.wait(1000);
console.log(`Iteration: ${times}`);
console.log('Here goes your code.');
return times < 5;
});
While cy.wrap().each() will work (one of the answers given for this question), I wanted to give an alternate way that worked for me. cy.wrap().each() will work, but regular while/for loops will not work with cypress because of the async nature of cypress. Cypress doesn't wait for everything to complete in the loop before starting the loop again. You can however do recursive functions instead and that waits for everything to complete before it hits the method/function again.
Here is a simple example to explain this. You could check to see if a button is visible, if it is visible you click it, then check again to see if it is still visible, and if it is visible you click it again, but if it isn't visible it won't click it. This will repeat, the button will continue to be clicked until the button is no longer visible. Basically the method/function is called over and over until the conditional is no longer met, which accomplishes the same thing as a for/while loop, but actually works with cypress.
clickVisibleButton = () => {
cy.get( 'body' ).then( $mainContainer => {
const isVisible = $mainContainer.find( '#idOfElement' ).is( ':visible' );
if ( isVisible ) {
cy.get( '#idOfElement' ).click();
this.clickVisibleButton();
}
} );
}
Then obviously call the this.clickVisibleButton() in your test. I'm using typescript and this method is setup in a class, but you could do this as a regular function as well.
// waits 2 seconds for each attempt
refreshQuote(attempts) {
let arry = []
for (let i = 0; i < attempts; i++) { arry.push(i) }
cy.wrap(arry).each(() => {
cy.get('.quote-wrapper').then(function($quoteBlock) {
if($quoteBlock.text().includes('Here is your quote')) {
}
else {
cy.get('#refreshQuoteButton').click()
cy.wait(2000)
}
})
})
}
Try template literals using backticks:
for(let i = 0; i < 3; i++){
cy.get(`ul li:nth-child(`${i}`)).click();
}

"_mock.default.unsubscribe is not a function" React using mock.js can't unsubscribe

Will attach full example of this task mock.js unsubscribe. I have a store reducer (tbodyCommand.reducer.js) that needs to take 10 rows from data by subscribing it and than after that it have to be unsubscribed. I am using standard .unsubscribe() method, but it goes to TypeError _mock.default.unsubscribe is not a function. How can i turn off my subscribing?
I found similar question over here unsubscribe is not a function on an observable where main problem appears in RxJS version but mine seems to work good for me. The example of syntax construction over here with subscribe method doesn't contain any way to deal with mock.js; How can I use it in my example so it will work? Is there any other ways to come to this problem simpler?
method
Got changed properties$.subscribe to variable and took out return from subscribe function.
var row_temp = [];
const makeTbodyArray = () => {
properties$.subscribe((data) => { // this stuff need to go in variable
if (row_temp.length < 11) {
row_temp.push(data);
} else {
properties$.unsubscribe();
return row_temp; // taking out return
}
});
};
to
var row_temp = [];
const makeTbodyArray = () => {
let subscription = properties$.subscribe((data) => {
if (row_temp.length < 11) {
row_temp.push(data);
} else {
subscription.unsubscribe();
}
});
return row_temp; // like that
};

stop setInterval and if not work in react native function

I have the code below:
contaTempo(){
setInterval(() => this.setState({tempo: this.state.tempo+1}), 1000)
if (this.state.tempo >= 5) {
this.props.navigation.navigate('Sobre')
}
}
The setInterval works correctly but the if doesn't work. Also, the timer neve stops. Any help?
The if is running right away.
You want to place it inside the function passed to setInterval.
Also, you probably want to remove the timer as well, so call clearInterval() on the value returned by setInterval.
Furthermore, to prevent adding more than necessary to the this.state.tempo, move it to the else of the if statement.
Changed code would be like:
contaTempo(){
let myInterval = setInterval(() => {
if (this.state.tempo >= 5) {
clearInterval(myInterval);
this.props.navigation.navigate('Sobre')
} else {
this.setState({tempo: this.state.tempo+1});
}
}, 1000)
}

jest enzyme reactJS - method executes regardless of return

I have the following method I want to test:
handleDayClick(e, day, {disabled}) {
if (disabled) {
// Do not update the state if the day is disabled
return;
}
this.setState({ selectedDay: day });
this.props.dateClick(day);
};
So I wrote a mock function, passed it as a prop and figured I would test state and if the function gets called:
it('handleDayClick() should NOT set state.selectedDay, call props.dateClick when disabled', () => {
let mockDateClick = jest.fn();
const sidebar = shallow(<Sidebar dateClick={mockDateClick}/>);
let e = 'whatever';
let day = 'tomorrow';
sidebar.instance().handleDayClick(e, day, true);
expect(sidebar.state().selectedDay).toBe(undefined);
expect(mockDateClick).toNotHaveBeenCalled();
});
The thing is that the state().selectedDay gets set to tomorrow. The value before calling the method is 2017-01-12T18:18:13.216Z, so I am pretty sure the method does not exit on the render function.
What am I doing wrong?
In your test, you are doing: sidebar.instance().handleDayClick(e, day, true);
while handleDayClick is destructuring an object with the disabled key
handleDayClick(e, day, {disabled}) {
}
Try to call it like this : sidebar.instance().handleDayClick(e, day, { disabled: true });
In the future you might want to use tools like Flow to prevent errors https://flowtype.org/docs/react.html
you would have been able to detect it earlier by doing something like this :
handleDayClick(e: {}, day: string, {disabled}: boolean) {
}

Resources