提问人:Finlay Foulds 提问时间:11/17/2023 更新时间:11/17/2023 访问量:18
useEffect 依赖数组中的 window.innerwidth 未调用回调函数
window.innerwidth in useEffect dependency array is not calling the callback function
问:
该组件应该在初始渲染时在 h2 元素中显示日期、日期和月份。函数内部的 useEffect 旨在在 window.innerWidth < 735px 时将日期更改为短格式,并在非 735px 时将日期更改为长格式。它还旨在在日期更改时重新呈现组件。useEffect 回调函数在第一次渲染时被调用,并根据日期和 innerWidth 完全按预期显示日期,但当日期或 innerWidth 更改时不会再次显示,尽管 day、date、month 和 innerWidth 都包含在依赖数组中,使用 setInterval 函数每 2 秒检查一次日期。
我的代码:
import { useState, useEffect } from "react"
let formattedDate
let currentDate = new Date
export default function LocalDate() {
const [date, setDate] = useState("")
useEffect(() => {
const interval = setInterval(() => {
currentDate = new Date
}, 2000)
console.log("called")
if (window.innerWidth < 735) {
formattedDate = currentDate.toLocaleDateString("en-US", { weekday: "short", day: "numeric", month: "short" })
} else {
formattedDate = currentDate.toLocaleDateString("en-US", { weekday: "long", day: "numeric", month: "long" })
}
let parts = formattedDate.split(" ")
let formattedDateSwapped = `${parts[0]} ${parts[2]} ${parts[1]}`
setDate(formattedDateSwapped)
return clearInterval(interval)
}, [currentDate.getDay(), currentDate.getDate(), currentDate.getMonth(), window.innerWidth])
return (
<h2 id="date">{date}</h2>
)
}
我已经看过无数次了,用谷歌搜索了类似的问题,在许多论坛上都找不到答案。如果有人对我的问题有任何建议或解决方案,将不胜感激。请记住,我大约一周前才开始学习反应。谢谢
答:
我认为您需要使用状态对象来允许useEffect检测更改。 例如,如果创建此状态:
const [currentWidth, setCurrentWidth] = useState(0);
然后,您可以使用间隔每 x 秒填充一次此状态:
const interval = setInterval(() => {
setCurrentWidth(window.innerWidth);
}, 2000)
现在,您可以在 useEffect 控件中使用它:
useEffect(() => { /*do stuff*/ }, [currentWidth])
我希望这能帮到你。
这不起作用的原因是窗口宽度的更改(特别是 )不会在依赖项数组中创建更改。在监听窗口时,我发现简单地添加和删除事件侦听器(例如 /)是很好的方法......window
useEffect
addEventListener
removeEventListener
您不依赖于状态来侦听和更改页面宽度的定义值。
当组件更改或卸载时,能够控制它们(即清除它们)也是一种很好的做法(在使用超时和间隔时)(这样您就不会发生内存泄漏)。
我习惯于这样(以及下面)定义它们,因为它非常明确地说明您在超时时做什么。使用 s 也不会在更改值时导致重新呈现。
React Docs 在“何时使用 refs”中也提到了这一点。ref
timeout.current
const { useState, useEffect, useRef } = React
const shortDate = { weekday: "short", day: "numeric", month: "short" }
const longDate = { weekday: "long", day: "numeric", month: "long" }
const formatDate = () => {
const currentDate = new Date();
return window.innerWidth < 735
? currentDate.toLocaleDateString("en-US", shortDate)
: currentDate.toLocaleDateString("en-US", longDate);
}
function LocalDate () {
const [formattedDate, setFormattedDate] = useState(formatDate());
const intervalRef = useRef(null)
useEffect(() => {
const getNewDate = () => {
setFormattedDate(formatDate());
console.log("called");
}
const getNewDateInterval = () => {
if (intervalRef.current) {
console.log("cleared 1")
clearInterval(intervalRef.current)
}
intervalRef.current = setInterval(getNewDate, 2000)
}
// call once to start off
getNewDateInterval()
// add listener
window.addEventListener("resize", getNewDate);
// clean up
return () => {
if (intervalRef.current) {
console.log("cleared 2")
clearInterval(intervalRef.current)
}
window.removeEventListener("resize", getNewDate);
}
}, [])
return (
<h2 id="date">{formattedDate}</h2>
)
}
// Render it
ReactDOM.createRoot(
document.getElementById("root")
).render(
<LocalDate />
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>
评论