0

I am a complete noob of react-native. My goal is to increase or decrease a counter till the user keeps a button pressed. For that, I am using onLongPress prop of toucableopacity and trying to change a state with that at a delay of 400ms using SetTimeout() function.
But when the longpress activates it changes the value once and then it doesn't change it anymore. I looked up related issues and everyone is mentioning that it's because setstate is asynchronous. But why would it update the value once before calling the timeout?
So my initial guess is it's something to do with the settimeout. Or if anyone has any other solution to executing the desired action please help me out.

import React, { Component, useState } from 'react';
import { StyleSheet, View, TouchableOpacity, Text } from 'react-native';
let timer = null;

function Untitled(props) {
  const [counter, setcounter] = useState(50);
  let dummy = counter;

  const timerhandler = () => {
    setcounter(counter - 1);
    console.log(counter);
    timer = setTimeout(timerhandler, 400);
  };

  const stopTimer = () => {
    console.log(counter);
    clearTimeout(timer);
  };
  return (
    <View style={styles.container}>
      <View style={styles.buttonStackStack}>
        <TouchableOpacity
          style={styles.button16}
          onLongPress={timerhandler}
          onPressOut={stopTimer}>
          <Text>Minus</Text>
        </TouchableOpacity>
        <Text>{counter}</Text>
        <TouchableOpacity style={styles.button16}>
          <Text>Plus</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}
export default function App() {
  return Untitled();
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'rgba(173,216,230,1)',
    borderWidth: 1,
    borderColor: '#000000',
    flexDirection: 'column',
    margin: 10,
  },
  buttonStackStack: {
    flex: 1,
    backgroundColor: 'rgba(173,216,230,1)',
    borderWidth: 1,
    borderColor: '#000000',
    flexDirection: 'row',
    alignItems: 'center',
    paddingTop: 5,
    justifyContent: 'center',
  },
  button16: {
    flex: 1,
    backgroundColor: 'rgba(173,216,230,1)',
    borderWidth: 1,
    borderColor: '#000000',
    alignItems: 'center',
    margin: 10,
    justifyContent: 'center',
  },
});

And also the settimeout does keep the loop running until stopTimer is called which can be confirmed by console.log() outputs.

  • 1
    Does this answer your question? [State not updating when using React state hook within setInterval](https://stackoverflow.com/questions/53024496/state-not-updating-when-using-react-state-hook-within-setinterval) – Andy Ray Dec 02 '20 at 02:31
  • Try adding `delayLongPress={1000}` – Nooruddin Lakhani Dec 02 '20 at 06:28
  • delayLongPress didn't work. But a friend of mine suggested me to try out reducer and that actually worked out for me. so I am still not sure what id the initial problem but for now, I will be using reducer. I am adding my solution as an answer. – Mashur Shalehin Dec 03 '20 at 03:56

1 Answers1

0

So I am still not sure what is the real issue here. But with help from a friend I worked around the problem using the reducer instead. Here is the new code that is working for me.

import React, { Component, useState, useReducer } from 'react';
import { StyleSheet, View, TouchableOpacity, Text } from 'react-native';
let timer = null;
function reducer(state, action){
  if(action.type == 'minus'){
    if(state.count>1){
    console.log(state.count-1)
    return {count: state.count-1}}
    return state}
  else if(action.type == 'plus'){
    if(state.count<100){
    console.log(state.count+1)
    return {count: state.count+1}}
    return state}
}
function Untitled(props) {
  const [state, dispatch] = useReducer(reducer, {count:50});

  const timerhandler = () => {
    dispatch({type:'minus'})
    timer = setTimeout(timerhandler, 200);
  };
  const timerhandler2 = () => {
    dispatch({type:'plus'})
    timer = setTimeout(timerhandler2, 200);
  };

  const stopTimer = () => {
    // console.log(state.count);
    clearTimeout(timer);
  };
  return (
    <View style={styles.container}>
      <View style={styles.buttonStackStack}>
        <TouchableOpacity
          style={styles.button16}
          onLongPress={timerhandler}
          onPressOut={stopTimer}>
          <Text>Minus</Text>
        </TouchableOpacity>
        <Text>{state.count}</Text>
        <TouchableOpacity style={styles.button16}
          onLongPress={timerhandler2}
          onPressOut={stopTimer}>
          <Text>Plus</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}
export default function App() {
  return Untitled();
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'rgba(173,216,230,1)',
    borderWidth: 1,
    borderColor: '#000000',
    flexDirection: 'column',
    margin: 10,
  },
  buttonStackStack: {
    flex: 1,
    backgroundColor: 'rgba(173,216,230,1)',
    borderWidth: 1,
    borderColor: '#000000',
    flexDirection: 'row',
    alignItems: 'center',
    paddingTop: 5,
    justifyContent: 'center',
  },
  button16: {
    flex: 1,
    backgroundColor: 'rgba(173,216,230,1)',
    borderWidth: 1,
    borderColor: '#000000',
    alignItems: 'center',
    margin: 10,
    justifyContent: 'center',
  },
});