I have two inputs whose values reflect the state of a counter.
The first input sets the state immediately as its value changes. This input can represent other parts of the application changing state.
The second input part of a component I made named LazyInput. LazyInput doesn't update state immediately, only when it's blurred, which I think gives a better usability. This input can represent the user input, like a timer to be set or the position of something on the screen.
However, I would like the LazyInput not to behave "lazily" and actually update the counter immediately only when the value is changed via the ↑ ↓ keys.
The App code (which includes the normal input) is the following:
const {Fragment, useState, useEffect} = React;
function LazyInput({ name, value, onComplete }) {
  const initialValue = value;
  const [lazyValue, setLazyValue] = useState(value);
  // Sync to state changed by the regular input
  useEffect(() => {
    setLazyValue(value);
  }, [value]);
  const handleKeyDown = e => {
    const { key, target } = e;
    switch (key) {
      case "ArrowUp": {
        setLazyValue(parseFloat(lazyValue) + 1);
        onComplete(e);
        break;
      }
      case "ArrowDown": {
        setLazyValue(parseFloat(lazyValue) - 1);
        onComplete(e);
        break;
      }
      case "Escape": {
        setLazyValue(initialValue);
        target.blur();
        break;
      }
      case "Enter": {
        target.blur();
        break;
      }
      default:
        return;
    }
  };
  return (
    <input
      name={name}
      value={lazyValue}
      onChange={e => setLazyValue(e.target.value)}
      onKeyDown={e => handleKeyDown(e)}
      onBlur={e => onComplete(e)}
    />
  );
}
function App() {
  const [counter, setCounter] = useState(0);
  function handleCounterChange(e) {
    setCounter(parseFloat(e.target.value));
  }
  return (
    <Fragment>
      <div>Counter: {counter}</div>
      <LazyInput
        name="counter"
        value={counter}
        onComplete={e => handleCounterChange(e)}
      />
      <input
        value={counter}
        type="number"
        onChange={e => handleCounterChange(e)}
      />
    </Fragment>
  );
}
ReactDOM.render(<App />, document.getElementById("app"));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="app"></div>
The problem is: pressing the ↑ ↓ keys fires the onComplete(e) function before the setLazyValue() – I suppose because it's asynchronous – losing sync with the state.
For the same reason, pressing Esc blurs the input before resetting its value to initialValue.
I know the setState() class callback has been substituted by the useEffect() hook, but:
- How do I call the 
onComplete(e)function – like any other event – fromuseEffect()? - How do I do that only when the ↑ ↓ keys are pressed, but not for all other keys?
 
Thanks in advance for you help, here's an interactive sandbox.