Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

173
Vistas
Increasing a value non-linearly when holding down a button (React)

I apologize if this has been asked before, but I haven't found anything to help me quite yet, and I am new to React!

I want a value to increase every n number of seconds a user holds down a button. Right now it is just increasing linearly ever 35 milliseconds!

So far I have something like this:

function Increaser() {

  const [value, setValue] = useState(0);
  const changeTimer: React.MutableRefObject<any> = useRef(null);

  function timeoutClearUp() {
    clearInterval(changeTimer.current);
  }

  function increment() {
    changeTimer.current = setInterval(() => setValue(prev => prev + 1), 35);
  };

  function onChange(e: any) {
    setValue(parseInt(e.target.value));
  }

  return (
    <div>
      <button onMouseUp={timeoutClearUp} onMouseDown={increment}>INCREASE</button>
      <input
            type="number"
            value={value}
            onChange={(e) => {onChange(e)}}
          />
    </div>
  );
}

I have tried adding another ref but it didn't seem to work! What is a small thing I can add to this code to ensure that every second value is incremented by a larger and larger value (the longer a user holds the button down for).

Thanks so much!

  • React: ^17.0.2
  • Typecript: ^4.5.5
about 4 years ago · Juan Pablo Isaza
3 Respuestas
Responde la pregunta

0

Because nobody gave you a real solution, here is one such way of doing what you want.
What I have done here is to use a refrence to the input, and have the value in your state updated once they stop clicking the increment button, or when they change the input manually.
In the increment function I use a setTimeout to create a custom interval, and this interval uses a math equation to determine what the next timeout/interval will be. The equation I used will go from 35ms (start) to 10ms (end) in 41 seconds and will not go below 10ms.
Here is a time chart of what I use in this example for speeding up the interval. (the x axis is time in seconds, and y axis is the delay in milliseconds) Graph of time function I used.

import { useState, useRef } from 'react';

function Increaser() {

    const [value, setValue] = useState(0);
    const myInputRef = useRef<HTMLInputElement>(null);
    let myTimeout: ReturnType<typeof setTimeout>;
    let startTime: Date;

    function stopInterval() {
        clearTimeout(myTimeout!);//Stop the interval in essence
        setValue(parseInt(myInputRef.current!.value!)||0) //Set the value of the input (in the mean time value is "floating")
    }
  
    function increment() {
      startTime = new Date();//Initialize when we started increasing the button
      myTimeout = setTimeout(function runIncrement() {//Start the timeout which is really a controlled interval
        const val = (parseInt(myInputRef!.current!.value)||0)+1;//Increment the value of the ref's target
        myInputRef!.current!.value = (val).toString()//Assign that incremented value to the ref
        const now = new Date();
        const delta = now.getTime() - startTime.getTime();
        const n = 10 + (1/(Math.pow(1.1,delta/1000-(2*Math.log(5))/Math.log(1.1))));//Whatever
        //The math function I have chosen above will go from 35 ms to 10 ms in 41 seconds.
        //The function will not go lower than 10 ms and starts at 35 ms
        //However you can use whatever function or math you want to get it to do as you wish.
        //...
        //whatever logic here you want to calculate when we will trigger the increment again.
        //...
        myTimeout = setTimeout(runIncrement, parseInt(n.toString()));//Increment again after the variable n milliseconds which we calculate above
      },35);//Start the interval with an initial time of 35 milliseconds
      //Now we know when the interval started, and we can
    };
  
    function onChange(e: any) {
      setValue(parseInt(e.target.value));
    }
  
    return (
      <div>
        <button onMouseUp={stopInterval} onMouseDown={increment}>INCREASE</button>
        <input
              type="number"
              onChange={(e) => {onChange(e)}}
              ref={myInputRef}
            />
      </div>
    );
  }
export default Increaser;

`

I appologize for the slight formatting that S.O. is doing here (in combination with my VS code editor).

about 4 years ago · Juan Pablo Isaza Denunciar

0

Thanks to SharpInnovativeTechnologies' answer, I realized how dumb I was and found an easy solution by going:

  function increment() {
    const past = Date.now()
    const rate = 500;
    changeTimer.current = setInterval(() => {
        const diff = Math.floor((Date.now() - past) / rate);
        setValue(prev => prev + (1 + diff))
      }, 50);
    }

Where rate is a sort of sensitivity adjustment.

So every 50ms The Date.now() - past increases and boosts the value with the setter.

about 4 years ago · Juan Pablo Isaza Denunciar

0

If you want to grow every second, you should change

...
changeTimer.current = setInterval(() => setValue(prev => prev + 1), 35);

...
<input
  type="number"
  value={value}
/>

to

...
changeTimer.current = setInterval(() => setValue(prev => prev + 35), 35);

...
<input
  type="number"
  value={value/1000}
/>

because the second parameter of setInterval is milliseconds.

Full code and demo:

Edit TextField selectionStart

import React, { useState, useRef } from "react";

export default function Increaser() {
  const [value, setValue] = useState(0);

  const changeTimer = useRef(null);

  function timeoutClearUp() {
    if (changeTimer.current) {
      clearInterval(changeTimer.current);
      changeTimer.current = null;
    }
  }

  function increment() {
    changeTimer.current = setInterval(() => {
      setValue((prev) => prev + 35);
    }, 35);
  }

  return (
    <div>
      <button onMouseUp={timeoutClearUp} onMouseDown={increment}>
        INCREASE
      </button>
      <button
        onClick={() => {
          setValue(0);
        }}
      >
        Reset
      </button>
      <div>{value / 1000}</div>
    </div>
  );
}

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda