[英]How to call event from component after setting its state with React hooks?
我有兩個input
,它們的值反映了計數器的狀態。
第一個input
在其值更改時立即設置狀態。 此input
可以表示應用程序更改狀態的其他部分。
我創建的名為LazyInput
的組件的第二個input
部分。 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>
問題是:按下↑ ↓鍵會在setLazyValue()
之前觸發onComplete(e)
函數——我想是因為它是異步的——與狀態失去同步。
出於同樣的原因,在將input
值重置為initialValue
之前按Esc 會模糊input
。
我知道setState()
類回調已被useEffect()
hook 替代,但是:
useEffect()
調用onComplete(e)
函數——就像任何其他事件一樣?預先感謝您的幫助,這是一個交互式沙箱。
我建議將counter
和setCounter
傳遞給LazyInput
以便可以直接訪問它們。 useEffect
可以被賦予一個依賴數組,只有當它的一個依賴改變時它才會觸發。 但是, useEffect
不適合這種情況。 您可以將counter
指定為useEffect
的依賴項,但每次更改counter
的值時它都會觸發。 useEffect
只能觀察變量,不能向它傳遞值。 我建議閱讀這篇文章以了解useEffect
工作原理以及何時使用它。
https://overreacted.io/a-complete-guide-to-useeffect/
我的解決方案將counter
和setCounter
傳遞給LazyInput
。 如果您希望LazyInput
保留自己的狀態,您可以使用useEffect
來觀察lazyValue
。 當lazyValue
改變時, counter
應該更新。
這是我的解決方案:
const {Fragment, useState, useEffect} = React; function LazyInput({ name, counter, setCounter }) { const [initialValue] = useState(counter); const handleKeyDown = e => { const { key, target } = e; switch (key) { case "ArrowUp": { setCounter(counter + 1); break; } case "ArrowDown": { setCounter(counter - 1); break; } case "Escape": { setCounter(initialValue); target.blur(); break; } case "Enter": { target.blur(); break; } default: return; } }; return ( <input name={name} value={counter} onChange={e => setCounter(e.target.value)} onKeyDown={e => handleKeyDown(e)} /> ); } function App() { const [counter, setCounter] = useState(0); return ( <Fragment> <div>Counter: {counter}</div> <LazyInput name="counter" counter={counter} setCounter={setCounter} /> <input value={counter} type="number" onChange={e => setCounter(parseFloat(e.target.value))} /> </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>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.