我还在研究react钩子,但很难发现我做错了什么。我有一个调整面板大小的组件,onmousedown
的一个边,我更新了状态的值,然后有一个mousemove
的事件处理程序,它使用了这个值,但是在值改变后,它似乎没有更新。
下面是我的代码:
export default memo(() => {
const [activePoint, setActivePoint] = useState(null); // initial is null
const handleResize = () => {
console.log(activePoint); // is null but should be 'top|bottom|left|right'
};
const resizerMouseDown = (e, point) => {
setActivePoint(point); // setting state as 'top|bottom|left|right'
window.addEventListener('mousemove', handleResize);
window.addEventListener('mouseup', cleanup); // removed for clarity
};
return (
<div className="interfaceResizeHandler">
{resizePoints.map(point => (
<div
key={ point }
className={ `interfaceResizeHandler__resizer interfaceResizeHandler__resizer--${ point }` }
onMouseDown={ e => resizerMouseDown(e, point) }
/>
))}
</div>
);
});
问题出在handleResize
函数上,该函数应使用最新版本的activePoint
,该版本应为字符串top|left|bottom|right
,但实际上为null
。
8条答案
按热度按时间pes8fvy91#
如何修复过时的
useState
目前,您的问题是您正在阅读过去的值。当您定义
handleResize
时,它属于该呈现器,因此,当您重新呈现时,事件侦听器不会发生任何变化,因此它仍然从其呈现器读取旧值。有几种方法可以解决这个问题。首先让我们看看最简单的解决方案。
在作用域中创建函数
鼠标按下事件的事件侦听器将
point
值传递给resizerMouseDown
函数。该值与activePoint
的值相同,因此可以将handleResize
函数的定义移到resizerMouseDown
和console.log(point)
中。由于此解决方案非常简单,它不能说明需要在另一个上下文中访问resizerMouseDown
之外的状态的情况。See the in-scope function solution live on CodeSandbox.
useRef
读取未来值一个更通用的解决方案是创建一个
useRef
,每当activePoint
发生变化时,您就更新它,这样您就可以从任何陈旧的上下文中读取当前值。See the
useRef
solution live on CodeSandbox.附录
应该注意的是,这些并不是解决此问题的唯一方法,但这些是我的首选方法,因为尽管某些解决方案比其他解决方案要长,但我认为逻辑更清晰。请使用您和您的团队最了解并找到最能满足您特定需求的解决方案;但是不要忘记记录代码的功能。
ki0zmccv2#
您可以从setter函数访问当前状态,因此可以使其:
z3yyvxxp3#
useRef
为回调与安德里亚的方法类似,可以使用
useRef
来更新事件侦听器的回调本身,而不是useState
值。这允许您在一个回调中使用许多最新的useState
值,而只有一个useRef
。如果使用
useRef
创建ref,并在每次渲染时将其值更新为handleResize
回调,则存储在ref中的回调将始终可以访问最新的useState
值,并且handleResize
回调将可供任何过时的回调(如事件处理程序)访问。考虑到这一点,我们还可以将ref的创建和更新抽象到一个自定义钩子中。
示例
See it live on CodeSandbox.
9rnv2umw4#
ryhaxcpt5#
这只是对克里斯·布朗尼55的建议的小小补充。
可以实现一个自定义钩子以避免重复此代码,并以与标准
useState
几乎相同的方式使用此解决方案:tcomlyy66#
对于使用typescript的用户,可以使用以下函数:
并这样称呼它:
并且当您调用
setRecordingState
时,它将自动更新ref和状态。rkkpypqq7#
你可以使用useEffect钩子,并在每次activePoint改变时初始化事件监听器。这样你可以最大限度地减少代码中不必要的引用。
z31licg08#
当您需要在组件装载时添加事件侦听器时
* 使用,useEffect()挂接 *
我们需要使用useEffect来设置事件监听器和清除相同的事件。
使用效果相依性清单需要有事件行程常式中使用的状态变数。这将确保行程常式不会存取任何过时的事件。
请看下面的例子。我们有一个简单的
count
状态,当我们点击给定的按钮时,它会递增。Keydown
事件监听器会打印相同的状态值。如果我们从依赖列表中删除count
变量,我们的事件监听器会打印旧的状态值。