[英]Why does this simple React component throw an error when I try to run it?
This is a trivial analog clock that seems simple enough.这是一个看起来很简单的微不足道的模拟时钟。 However, it seems to fail at line 7 with "TypeError: Cannot read properties of null (reading 'style')".
但是,它似乎在第 7 行失败,并显示“TypeError:无法读取 null 的属性(读取 'style')”。 I've also tried the setAttribute() method and get the same thing.
我也尝试过 setAttribute() 方法并得到同样的结果。 How do I dynamically update the rotation every second?
如何每秒动态更新旋转?
export const Analog = () => {
function setDate() {
let secondHand = document.querySelector(".second-hand");
const now = new Date();
const seconds = now.getSeconds();
const secondsDegrees = (seconds / 60) * 360 + 90;
secondHand.style.transform = `rotate(${secondsDegrees}deg)`;
}
setInterval(setDate, 1000);
return (
<svg id="clock" className="min-w-full min-h-full" viewBox="0 0 100 100">
<circle id="face" cx="50" cy="50" r="50" />
<g id="hands">
<circle id="center" cx="50" cy="50" r="2" fill="white" />
<line
id="secondHand"
className="second-hand"
x1="50"
y1="50"
x2="50"
y2="0"
/>
</g>
</svg>
);
};
In react you should almost never need to do direct dom manipulation, and definitely not for the scenario you have here.在反应中,您几乎不需要直接进行 dom 操作,而且绝对不需要您在这里的场景。 Instead, you should use a state variable to track how much it's supposed to be rotated, and use that variable in the render output.
相反,您应该使用 state 变量来跟踪它应该旋转多少,并在渲染 output 中使用该变量。 Additionally, you don't want to set an interval in the body of your component, as that will result in an ever increasing number of intervals.
此外,您不想在组件主体中设置间隔,因为这会导致间隔数量不断增加。
useEffect
should be used instead.应该使用
useEffect
代替。
export const Analog = () => {
const [secondsDegrees, setSecondsDegrees] = useState(0);
useEffect(() => {
const id = setInterval(() => {
const now = new Date();
const seconds = now.getSeconds();
setSecondsDegrees((seconds / 60) * 360 + 90);
}, 1000);
return () => clearInterval(id);
}, []);
return (
<svg id="clock" className="min-w-full min-h-full" viewBox="0 0 100 100">
<circle id="face" cx="50" cy="50" r="50" />
<g id="hands">
<circle id="center" cx="50" cy="50" r="2" fill="white" />
<line
id="secondHand"
className="second-hand"
style={{ transform: `rotate(${secondsDegrees}deg)` }}
x1="50"
y1="50"
x2="50"
y2="0"
/>
</g>
</svg>
);
}
Is there any other element using second-hand
, I assume not?是否有任何其他元素使用
second-hand
,我假设没有? At each render, your function will run before the element is returned, hence your secondHand
is undefined
.在每次渲染时,您的 function 将在元素返回之前运行,因此您的
secondHand
是undefined
。
It could be timing issues between executing the setInterval
and actual mounting of the component ( <Analog />
) itself.执行
setInterval
和实际安装组件 ( <Analog />
) 本身之间可能存在时间问题。 You should use componentDidMount
in case of class components or you can use useEffect
in case of functional component.如果是 class 组件,您应该使用
componentDidMount
,或者如果是功能组件,您可以使用useEffect
。
NOTE: Try not to bypass React in order to access DOM (like document.querySelector()
).注意:尽量不要绕过 React 来访问 DOM(如
document.querySelector()
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.