I have been stuck on this problem for quite some time. I am making a matrix style themed blog that displays matrix rain effect in the background when the displayMatrix rain state in my Store becomes true, and stops displaying matrix rain effect when displayMatrix becomes false. I need to use setInterval to draw the matrix rain effect, inside the setInterval I call the 'draw' function that has a loop inside that draws the matrix rain characters in the background using canvas tools. The problem I am encountering is that when I change displayMatrix state to true, and than to false later on, the loop keeps on running, and I never see the in the console log 'id being cleared is => #' even after i have changed displayMatrix state to be false. I have tried to mimic the barebones of my code in the following sandbox so you can see the overall structure of the code https://playcode.io/933189/. I am using reacts inbuilt useReducer/useContext hooks in place of redux. Another weird thing I noticed is that in the code sandbox, when i change displayMatrix state to be true, and afterwards turn it to be false, it at least stops the 'run matrix rain drawing code' in the console, but in my original code on VisualStudio Code, I keep seeing 'run matrix rain drawing code' in the console and it runs basically forever until it runs out of memory
import React from 'react';
import {useEffect, useContext, useState} from 'react';
import {GlobalStore} from '../Store.jsx';
export function App(props) {
const [state, dispatch] = useContext(GlobalStore);
const [intervalId, setIntervalId] = useState(0);
useEffect(() => {
const draw = () => {
// pretend 100 is the width of the screen
for (let i = 0; i < 100; i = 1)
{
console.log("run matrix rain drawing code");
}
}
// if we want to diplay the matrix rain
if (state.displayMatrix) {
// only create an interval when interval does
// not already exist
if (intervalId === 0) {
const id = setInterval(draw, 90);
console.log("id being set is => " id);
setIntervalId(id);
}
else {
console.log("id being cleared is => " intervalId);
clearInterval(intervalId);
setIntervalId(0);
}
}
// if we want to stop matrix rain
else {
console.log("id being cleared is => " intervalId);
clearInterval(intervalId);
setIntervalId(0);
}
}, [state.displayMatrix])
return (
<div>
<div onClick={() => dispatch({type: 'CHANGE_MATRIX_RAIN_BACKGROUND_DISPLAY_STATE'})}>Matrix Display {state.displayMatrix ? 'Off' : 'On'}</div>
</div>
)
}
CodePudding user response:
I have this timeCounter helper class
import { setIntervalAsync, clearIntervalAsync, SetIntervalAsyncTimer } from 'set-interval-async/fixed';
export class TimeCounter {
private interval: SetIntervalAsyncTimer | undefined;
private onRepeat: () => any;
private onStop: () => any;
constructor(onRepeat: () => any, onStop: () => any) {
this.onRepeat = onRepeat;
this.onStop = onStop;
}
startCounter(milliseconds: number) {
if (!this.isActive()) {
this.interval = setIntervalAsync(async () => {
this.onRepeat();
}, milliseconds);
}
}
stopCounter(): void {
if (this.interval !== undefined) {
this.onStop();
clearIntervalAsync(this.interval);
this.interval = undefined;
}
}
isActive(): boolean {
return this.interval !== undefined;
}
}
Usage:
export function useCounter() {
const counter = new TimeCounter(onRepeatCounter, () => null);
const [result, setResult] = useState(0);
useEffect(() => {
if (!counter.isActive() && defaultDate === undefined) {
counter.startCounter(1000);
}
return () => counter.stopCounter();
});
function onRepeatCounter() {
// Custom functionality
setResult((val) => val 1);
}
return result;
}
CodePudding user response:
playcode seems to work properly, just press Show More to see the log end.