reactjs useEffect依赖数组中的window.innerwidth未调用回调函数

wr98u20j  于 2023-11-18  发布在  React
关注(0)|答案(2)|浏览(121)

这个组件应该显示日期,初始呈现时h2元素中的日期和月份。函数内部的useEffect旨在window.innerWidth < 735px时将日期更改为短格式,当不是时将其更改为长格式。它还旨在**当日期更改时重新呈现组件。**useEffect回调函数在第一次呈现时被调用,并根据日期和innerWidth按预期完全显示日期,但当日期或innerWidth更改时不会再次显示,尽管日期,日期,month和innerWidth都包含在依赖数组中,每2秒检查一次日期使用setInterval函数。
我的代码:

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>
  )
}

字符串
我已经看了无数次,谷歌类似的问题,并期待在许多论坛,找不到答案。如果有人有任何建议或解决方案为我的问题,这将是**非常感谢。**请记住,我才开始学习React大约一个星期前。谢谢

zpf6vheq

zpf6vheq1#

这不起作用的原因是因为窗口宽度的变化(特别是window)并没有在useEffect依赖数组中创建变化。当涉及到监听窗口时,我发现简单的adding and removing event listeners(例如addEventListener/removeEventListener)是一个很好的方法。
您不依赖于状态来监听和更改页面宽度的定义值。
当组件更改或卸载时,能够控制(即清除)超时和间隔也是一个很好的做法(在处理超时和间隔时)(这样就不会出现内存泄漏)。
我习惯于像this(及以下)这样定义它们,因为它非常声明性,并且清楚地说明了你在做什么超时。使用ref s也不会在更改timeout.current值时导致重新渲染。
React开发者在“何时使用refs”中也提到了这一点。

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 />
);

个字符

gr8qqesn

gr8qqesn2#

我认为你需要使用state对象来允许useEffect检测变化。例如,如果你创建了这个state:

const [currentWidth, setCurrentWidth] = useState(0);

字符串
然后你可以使用一个interval来填充这个状态每隔x秒:

const interval = setInterval(() => {
  setCurrentWidth(window.innerWidth);
}, 2000)


现在你可以在useEffect控件中使用它:

useEffect(() => { /*do stuff*/ }, [currentWidth])


我希望这能帮助你。

相关问题