简体   繁体   English

使用 React 钩子设置状态后如何从组件调用事件?

[英]How to call event from component after setting its state with React hooks?

I have two input s whose values reflect the state of a counter.我有两个input ,它们的值反映了计数器的状态。

The first input sets the state immediately as its value changes.第一个input在其值更改时立即设置状态。 This input can represent other parts of the application changing state.input可以表示应用程序更改状态的其他部分。

The second input part of a component I made named LazyInput .我创建的名为LazyInput的组件的第二个input部分。 LazyInput doesn't update state immediately , only when it's blurred, which I think gives a better usability. LazyInput不会立即更新状态,只有在状态模糊时才更新,我认为这提供了更好的可用性。 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 .但是,我希望LazyInput不要“懒惰”地运行,并且仅在通过 键更改值时才实际立即更新计数器。

The App code (which includes the normal input ) is the following: 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>

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.问题是:按下 键会在setLazyValue()之前触发onComplete(e)函数——我想是因为它是异步的——与状态失去同步。

For the same reason, pressing Esc blurs the input before resetting its value to initialValue .出于同样的原因,在将input值重置为initialValue之前Esc 会模糊input

I know the setState() class callback has been substituted by the useEffect() hook , but:我知道setState()类回调已被useEffect() hook 替代,但是:

  1. How do I call the onComplete(e) function – like any other event – from useEffect() ?我如何从useEffect()调用onComplete(e)函数——就像任何其他事件一样?
  2. 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 .预先感谢您的帮助,这是一个交互式沙箱

I would recommend passing counter and setCounter down to LazyInput so they can be accessed directly.我建议将countersetCounter传递给LazyInput以便可以直接访问它们。 useEffect can be given a dependency array where it will only fire if one of its dependencies changes. useEffect可以被赋予一个依赖数组,只有当它的一个依赖改变时它才会触发。 However, useEffect is not right for this situation.但是, useEffect不适合这种情况。 You could assign counter as a dependency of the useEffect but it would fire every time the value of counter is changed.您可以将counter指定为useEffect的依赖项,但每次更改counter的值时它都会触发。 useEffect can only watch variables, you can't pass values to it. useEffect只能观察变量,不能向它传递值。 I suggest reading this article for learning about how useEffect works and when to use it.我建议阅读这篇文章以了解useEffect工作原理以及何时使用它。

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

My solution passes counter and setCounter to LazyInput .我的解决方案将countersetCounter传递给LazyInput If you want LazyInput to retain its own state, you can use a useEffect to watch lazyValue .如果您希望LazyInput保留自己的状态,您可以使用useEffect来观察lazyValue When lazyValue changes, the counter should be updated.lazyValue改变时, counter应该更新。

Here is my solution:这是我的解决方案:

 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.

相关问题 从另一个组件反应钩子设置状态 - Setting state from another component react hooks 如何使用 React 将状态从一个组件挂钩到另一个组件 - How to use React hooks state from one component to another Component React with Hooks:点击事件后如何正确更新状态? - React with Hooks: how to correctly update state after a click event? 如何从子组件反应钩子中仅更改 state 的一部分 - How to change only a part of the state from child component react hooks 从兄弟组件 React hooks 调用 function - Call function from sibling component React hooks 使用回调和挂钩(useState,useEffect)从父级中的 onClick 事件更改 React 子组件的 state - Change React child component's state from an onClick event in parent, with callbacks and hooks (useState, useEffect) 在 state 更改后,React 如何更新组件及其子组件? - How does React update a component and its children after a state change? 获取数据后设置 state 的问题(反应挂钩) - Problem with setting state after fetching data (React hooks) 如何正确地将数组从父 React 类组件状态传递给使用钩子编写的子组件? - How to properly pass an array from a parent React class component state to a child component written with hooks? 如何使用反应钩子将 state 从子组件传递给父组件? - How to use react hooks to pass a state from child component to the parent component?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM