skip to Main Content

I have a state value, it may change from time to time. I want to have a flag that indicate "this state has been staying in value x without any changes for y amount of time"

How do I achieve this?

P.S, if you played Oxygen Not Included, this is the logic I want: https://oxygennotincluded.fandom.com/wiki/FILTER_Gate

Update: can’t use setInterval/polling for this.

2

Answers


  1. The code in this answer is available at
    https://stackblitz.com/edit/react-qjmyix?file=src%2FApp.js

    The function useStateWithTimeFlag in the snippet below, returns an object with functions identical to those of setState, as well as a function for getting the elapsed time, and a variable with the elapsed time.
    You can use whichever you prefer.

    import React, { useState, useRef, useEffect, useCallback } from 'react';
    
    const useStateWithTimeFlag = (initValue) => {
      const [value, setValue] = useState(initValue);
      const [ElapsedTime, setElapsedTime] = useState(0);
      const timeRef = useRef(new Date());
    
      const getTime = useCallback(() => {
        return (new Date() - timeRef.current) / 1000;
      }, []);
    
      useEffect(() => {
        const i = setInterval(() => {
          setElapsedTime(getTime());
        }, 1000);
        return () => {
          clearInterval(i);
        };
      }, []);
    
      useEffect(() => {
        timeRef.current = new Date();
      }, [value]);
    
      return {
        value,
        setValue,
        getTime,
        ElapsedTime,
      };
    };
    

    The first useEffect hook updates the ElapsedTime variable once every second.
    The second hook resets the timer, whenever the state changes.

    This components shows how the function can be used.

    export default function App() {
      const { setValue, value, ElapsedTime, getTime } = useStateWithTimeFlag('');
    
      return (
        <div>
          <h1>Hello StackBlitz!</h1>
          <div>
            {' '}
            value: {value} stay there in {ElapsedTime} second{' '}
          </div>
          <div>
            {' '}
            value: {value} stay there in {getTime()} second{' '}
          </div>
          <input value={value} onChange={(e) => setValue(e.target.value)} />
        </div>
      );
    }
    
    
    Login or Signup to reply.
  2. without setInterval

    import React, { useState, useRef, useEffect, useCallback } from 'react';
    
    const useStateWithTimeFlag = (initValue) => {
      const [value, setValue] = useState(initValue);
      const timeRef = useRef(new Date());
    
      const getTime = useCallback(() => {
        return (new Date() - timeRef.current) / 1000;
      }, []);
    
      useEffect(() => {
        timeRef.current = new Date();
      }, [value]);
    
      return {
        value,
        setValue,
        getTime,
      };
    };
    
    export default function App() {
      const { setValue, value, getTime } = useStateWithTimeFlag('');
    
      return (
        <div>
          <h1>Hello StackBlitz!</h1>
          <div>{`value: ${value} stay there in ${getTime()} second`}</div>
          <button
            onClick={() => {
              console.log(`value: ${value} stay there in ${getTime()} second`);
            }}
          >
            show
          </button>
          <input value={value} onChange={(e) => setValue(e.target.value)} />
        </div>
      );
    }
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search