[英]Getting a Cannot read property 'style' of null Error When Using useRef Within a React Functional Component
I am trying to re-create this circle-follow-cursor effect found here but within a React functional component.我正在尝试重新创建这里找到的圆形跟随光标效果,但在 React 功能组件中。
const Button = props => {
const ballRef = React.useRef(null)
let mouseX = 0
let mouseY = 0
let ballX = 0
let ballY = 0
let speed = 0.2
function animate() {
let distX = mouseX - ballX
let distY = mouseY - ballY
ballX = ballX + distX * speed
ballY = ballY + distY * speed
ballRef.current.style.left = ballX + "px"
ballRef.current.style.top = ballY + "px"
requestAnimationFrame(animate)
}
animate()
document.addEventListener("mousemove", function(event) {
mouseX = event.pageX
mouseY = event.pageY
})
return (
<div ref={ballRef} >Button</div>
)
}
export default Button
The thing is, the code works the very first time I implemented it, then when I refresh the page it throws this error:问题是,代码在我第一次实现它时就起作用了,然后当我刷新页面时它会抛出这个错误:
TypeError: Cannot read property 'style' of null
animate
src/components/button/index.js:19
16 | let distY = mouseY - ballY
17 | ballX = ballX + distX * speed
18 | ballY = ballY + distY * speed
> 19 | ballRef.current.style.left = ballX + "px"
20 | ballRef.current.style.top = ballY + "px"
21 |
22 | requestAnimationFrame(animate)
I'm sure it's related to how React re-renders the UI based on changes but I thought the useRef hook helps with that.我确定这与 React 如何根据更改重新呈现 UI 相关,但我认为 useRef 挂钩对此有所帮助。 Anyway, I thought I'd get some fresh eyes on this.
无论如何,我想我会对此有所了解。
You need to set animate()
in useEffect
您需要在
useEffect
设置animate()
useEffect(() => {
animate();
}, []);
You're voilating several rules while using React Component and hooks, here's a much standard version of your code:您在使用 React Component 和 hooks 时违反了几条规则,这是您的代码的标准版本:
// Put the variables outside to make sure they won't reset while component refresh
let mouseX = 0
let mouseY = 0
let ballX = 0
let ballY = 0
let speed = 0.2
const Button = props => {
const ballRef = React.useRef(null);
// use useCallback to make sure this function won't create multiple copies when refreshed
const animate = React.useCallback(() => {
// Make sure the ballRef is created, at the first run, the ball ref is still null
if(ballRef && ballRef.current) {
let distX = mouseX - ballX
let distY = mouseY - ballY
ballX = ballX + distX * speed
ballY = ballY + distY * speed
ballRef.current.style.left = ballX + "px"
ballRef.current.style.top = ballY + "px"
}
requestAnimationFrame(animate)
}, [ballRef, mouseX, mouseY, ballX, ballY]);
// This make sure the function inside only runs when the component is mounted
React.useEffect(()=>{
const onMouseMove = event => {
mouseX = event.pageX;
mouseY = event.pageY;
};
document.addEventListener("mousemove", onMouseMove);
animate();
// When the component is unmount, remove the listener
return () => document.removeEventListener("mousemove", onMouseMove);
}, []);
return (
<div ref={ballRef} >Button</div>
)
}
export default Button
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.