[英]Building a React clock with hooks
我正在制作一個可以計數的時鍾,只是一個練習(我知道有更好的方法可以做到這一點)。
我的問題是當添加一分鍾時,“addMinute”似乎運行了兩次,而我終其一生都無法弄清楚如何或為什么。
這是關於代碼沙盒的演示: https://codesandbox.io/s/restless-frost-bud7p這里是代碼一目了然:
(請注意,計數器最多只能計數 3 並且計數更快;這僅用於測試目的)
const Clock = (props) => {
const [seconds, setSeconds] = useState(0)
const [minutes, setMinutes] = useState(0)
const [hours, setHours] = useState(0)
const addHour = () => {
setHours(p => p + 1)
}
const addMinute = () => {
setMinutes(prev => {
if (prev === 3) {
addHour()
return 0
} else {
return prev + 1
}
})
}
const addSecond = () => {
setSeconds(prevState => {
if (prevState === 3) {
addMinute()
return 0
} else {
return prevState + 1
}
})
}
useEffect(() => {
const timer = setInterval(addSecond, 600)
return () => clearInterval(timer)
}, [])
return (
<div>
<h1>time!</h1>
<p>
{hours < 10 ? 0 : ""}{hours}
:
{minutes < 10 ? 0 : ""}{minutes}
:
{seconds < 10 ? 0 : ""}{seconds}
</p>
<p>
{seconds.toString()}
</p>
</div>
)
}
問題是您在 index.js 文件中使用了 React.StrictMode 包裝器。
嚴格模式無法自動為您檢測副作用,但可以通過使它們更具確定性來幫助您發現它們。 這是通過有意雙重調用以下函數來完成的: https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects
所以你應該決定是使用嚴格模式還是有副作用,簡單的方法就是刪除 React.StrictMode 包裝器。 另一種方法是消除副作用,您只需要執行以下操作:
將您的 addSecond 和 addMinute 函數更新為:
const addMinute = () => {
setMinutes((prev) => prev + 1);
};
const addSecond = () => {
setSeconds((prevState) => prevState + 1);
};
您的 useEffect 調用如下:
useEffect(() => {
if(seconds === 3) {
addMinute();
setSeconds(0);
};
if(minutes === 3) {
addHour();
setMinutes(0);
}
const timer = setInterval(addSecond, 600);
return () => clearInterval(timer);
}, [seconds, minutes]);
這里是您的代碼的更新版本: https://codesandbox.io/s/goofy-lake-1i9xf
幾個問題,
首先你需要使用prev
幾分鍾,所以
const addMinute = () => {
setMinutes(prev => {
if (prev === 3) {
addHour()
return 0
} else {
return prev + 1
}
})
}
然后您需要從索引中刪除React.StrictMode
包裝器組件,這實際上是導致雙倍增加的原因,因為嚴格模式所做的一部分是
這是通過有意雙重調用以下函數來完成的:
Class 組件
constructor
、render
和shouldComponentUpdate
方法
Class 組件 staticgetDerivedStateFromProps
方法
Function 組件體
State 更新函數(setState
的第一個參數)
傳遞給useState
、useMemo
或useReducer
的函數
所以我不知道嚴格模式和有意的雙重渲染。 閱讀文檔后,我終於明白了這樣做的目的。
因此,似乎最好的解決方案是使 useEffect 沒有副作用,而是在效果之外處理該邏輯,但仍然每秒都在變化。
所以,我設置了一個效果,它有一塊 state 從零開始,每秒上升一個。
然后,隨着“時間”的每次變化,useMemo 將重新計算總時間的小時數、分鍾數和秒數。
我唯一不喜歡的是每次渲染都運行這些計算(但實際上這些計算只需要幾毫秒。所以性能似乎不是問題)。
const [time, setTime] = useState(0)
useEffect(() => {
const timer = setInterval(() => {
setTime(p => p + 1)
}, 999);
return () => clearTimeout(timer);
}, [userState]);
const timeJSON = useMemo(() => {
const hrs = Math.floor(time/3600)
const mins = Math.floor( (time-(3600*hrs)) / 60 )
const secs = time - (3600 * hrs) - (60*mins)
return {
hrs,
mins,
secs,
}
}, [time])
return (
<div>
<p>
{timeJSON.hrs < 10 ? 0 : ""}{timeJSON.hrs}
:
{timeJSON.mins < 10 ? 0 : ""}{timeJSON.mins}
:
{timeJSON.secs < 10 ? 0 : ""}{timeJSON.secs}
</p>
</div>
)
再次感謝大家為我指出正確的方向!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.