Vuex can't stop setInteval - vuex

I have a method in Vuex:
export const startTime = ({ commit, state }, status) => {
let timeInterval
if(status) {
const timer = 1000
timeInterval = setInterval(() => {
console.log('x')
commit('SET_RUNNED_TIME', parseInt(state.runnedTime += timer))
}, timer)
}
else {
console.log('y')
clearInterval(timeInterval)
commit('SET_RUNNED_TIME', 0)
}
}
From my component I send value true or false to method startTime(). When I send true then method run commit SET_RUNNED_TIME. But when I send false clearInterval(timeInterval) not stopping setInterval and still is sending commit('SET_RUNNED_TIME' ...)

The variable timeInterval is inside the scope of the function. If you want it to keep on living between different calls to startTime you need to put it outside the function scope. For example in the state.

Related

Vue clearInterval cant stop timer (reset timer)

I try to write function to restart setInterval timer:
data() {
return {
intervalId: undefined,
backlightTimerSeconds: 5000,
}
},
I have an method:
timerBacklightOff() {
const interval = 1000
this.intervalId = setInterval(() => {
this.backlightTimerSeconds -= interval
console.log('timerBacklightOff', this.backlightTimerSeconds)
if(this.backlightTimerSeconds <= 0) {
this.setBacklight(false)
this.clearTimerBacklight()
return
}
}, interval)
},
In antoher method I have method to clear interval:
clearTimerBacklight() {
if(!this.intervalId) return
this.backlightTimerSeconds = 0
clearInterval(this.intervalId)
this.intervalId = undefined
this.backlightTimerSeconds = 5000
},
I runned method clearTimerBacklight using button.
I have a problem, blecause when I running method clearTimerBacklight, then not stop setInterval and console.log('timerBacklightOff', this.backlightTimerSeconds) still counter down. How I can restart setInterval to basis time?

Is there a cleaner way to organize this recoilJS state?

I've just learned about recoilJS and have been playing around with it a bit and have a question about whether what I've done is considered "correct." My code works, but it feels weird.
I've got the following React function component:
export const TimerPanel: FC = () => {
const gameState = useRecoilValue<GameState>(HeaderAtoms.gameState);
const timerCount = useRecoilValue(HeaderAtoms.timerCount);
const setTimerCounter = useSetRecoilState(HeaderAtoms.timerCounter);
useEffect(() => {
if (gameState === GameState.IN_PROGRESS && timerCount < 1000) {
window.setTimeout(() => {
setTimerCounter(timerCount + 1);
}, 1000);
}
});
return <NumberPanel num={timerCount} />;
};
where the relevant atom and selector are defined as:
export const timerCount = atom<number>({
key: 'Header.timerCount',
default: 0
});
export const timerCounter = selector<number>({
key: 'Header.timerCounter',
get: ({ get }) => {
return get(timerCount);
},
set: ({ get, set }, newCount) => {
if (get(gameState) === GameState.NEW) {
set(timerCount, 0);
} else if (get(gameState) === GameState.IN_PROGRESS) {
set(timerCount, newCount);
}
}
});
Basically, when the game starts, the TimerPanel increments the timer display by 1 every second the game is in progress. If the user resets the game (GameState.NEW), timerCount resets back to zero. If the atom/selector aren't done properly, there's a race condition in that the game state and timer count will reset, but the timer is still going and will still update the TimerPanel one more time. This is why I have the if blocks in my selector's set prop.
Basically, I'm concerned that my timerCounter selector is a glorified filter/pass-thru entity for the timerCount state and am wondering if there's a better way to handle this use case.
If your concern is the race condition, in your code, I don't see how your timer would click. setTimeout will tick once.
Anyway, you have 2 states, game state and timer state. You want to reset timer when game state changes. How about doing it in a game state selector? or move the logic into a custom hook and operate on these 2 states directly.

Update a data value from a method called in mounted

I have this code and the goal from it is to update a data sticky to true if the scroll position is > than 0
export default {
components: {
},
data() {
return {
menuVisible: false,
sticky: false,
}
},
mounted() {
this.checkScroll()
},
methods: {
checkScroll() {
document.querySelector('body').onscroll = function() {
console.log(window.pageYOffset > 0)
this.sticky = window.pageYOffset > 0
}
},
},
}
the problem is that even that i see the true console logged, the data is allways false ( as the initial value )
Any idea why is not updating it?
That's because of the callback you're passing into your scroll listener. In your callback this is not the context of the vue component. I think its the body actually. You'll need to use an arrow function or pass the vue instance into the callback as an argument. Arrow function is easiest. An arrow function retains the context where it was defined rather than inheriting the context of the object that calls it. Here is a good post/answer about the difference between normal and arrow functions.
document.querySelector('body').onscroll = () => {
console.log(window.pageYOffset > 0)
this.sticky = window.pageYOffset > 0
}

How to get the array of object(song) to store in a variable

I want the url from the data to pass in the music player to play the song.
I'm unable to setState url in the song[] state.
componentWillMount(){
var ur_i = this.props.navigation.getParam('uri');
console.log(JSON.stringify(ur_i));
this.setState(this.state.song=ur_i)
alert(JSON.stringify(this.state.song.url))
}
I want song Url to be store in the song[].
Invalid setState usage method.
setState() operates asynchronously.
setState(updater[, callback])
The callback function of setState(updater[, callback]) is performed and is re-renderable.
Example
timerAction = () => {
const { time } = this.state;
console.log(time);
this.setState({
time: time - 1
})
console.log(time)
};
Usage
componentDidMount(){
var ur_i = this.props.navigation.getParam('uri');
console.log(JSON.stringify(ur_i));
this.setState(song:ur_i[0].song,() => alert(JSON.stringify(ur_i[0].song)))
}

My State value is not Changing ,when button is pressed

onButtonPress = () => {
min = 1000;
max = 9999;
randomotp = min + (Math.random() * (max - min));
console.log(Math.round(randomotp));
this.setState({
otpfield:'#48A23A'
});
console.log('result',this.state.otpfield);
}
}
I have been executing this function in the Button on click , but the corresponding (i,e Otpfield) value is not changing
React does not update the state immediately, it's an asynchronous operation. Therefore your console.log() call is invoked too fast and the state is not yet changed.
Use the "afterUpdated" callback instead (second parameter of the setState method):
this.setState(
{property: true},
() => console.log(this.state.property)
);
The state will not change. onButtonPress function must finish executing first before changing the state.
use componentDidUpdate lifecycle method to check if the state changed
componentDidUpdate(prevProps, prevState) {
console.log('result',this.state.otpfield);
//new State
console.log('result',prevState.otpfield);
// prev State
}