У меня есть два input
s, значения которых отражают состояние счетчика.
Первый input
устанавливает состояние немедленно при изменении его значения. Этот input
может представлять другие части изменяющегося состояния приложения.
Вторая input
часть компонента, которую я создал, с именем LazyInput
. LazyInput
не обновляет состояние немедленно , только когда оно размыто, что, на мой взгляд, повышает удобство использования. Этот ввод может представлять пользовательский ввод, например, установить таймер или положение чего-либо на экране.
Однако я бы хотел, чтобы LazyInput
не вел себя "лениво" и фактически немедленно обновлял счетчик. только при изменении значения с помощью клавиш ↑ ↓ .
Код App
(который включает в себя обычный input
) является следующим:
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>
Проблема заключается в следующем: нажатие клавиш ↑ ↓ вызывает функцию onComplete(e)
перед setLazyValue()
- я полагаю, потому что это асинхронно - потеря syn c с состоянием.
По той же причине нажатие Es c размывает input
до сброса его значения на initialValue
.
Я знаю, что обратный вызов класса setState()
был заменен хуком useEffect()
, но:
- Как вызвать функцию
onComplete(e)
- как и любое другое событие - из useEffect()
? - Как это сделать только тогда, когда ↑ ↓ Клавиши нажаты, но не для всех других клавиш?
Заранее спасибо за помощь, вот вам интерактивная песочница .