簡體   English   中英

使用 React 鈎子設置狀態后如何從組件調用事件?

[英]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 替代,但是:

  1. 我如何從useEffect()調用onComplete(e)函數——就像任何其他事件一樣?
  2. 僅當按下 鍵時我該怎么做,而不是所有其他鍵?

預先感謝您的幫助,這是一個交互式沙箱

我建議將countersetCounter傳遞給LazyInput以便可以直接訪問它們。 useEffect可以被賦予一個依賴數組,只有當它的一個依賴改變時它才會觸發。 但是, useEffect不適合這種情況。 您可以將counter指定為useEffect的依賴項,但每次更改counter的值時它都會觸發。 useEffect只能觀察變量,不能向它傳遞值。 我建議閱讀這篇文章以了解useEffect工作原理以及何時使用它。

https://overreacted.io/a-complete-guide-to-useeffect/

我的解決方案將countersetCounter傳遞給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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM