Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何在useEffect中使用useState?_Javascript_Reactjs_React Hooks_Next.js - Fatal编程技术网

Javascript 如何在useEffect中使用useState?

Javascript 如何在useEffect中使用useState?,javascript,reactjs,react-hooks,next.js,Javascript,Reactjs,React Hooks,Next.js,我试图将我的组件从react.component重构为hook,但遇到了一些麻烦。我真的不明白如何使用我的状态补偿。该值已设置,或者在需要时未设置 第一次尝试: const [offsetTop, setOffsetTop] = useState(); useEffect(() => { setOffsetTop(window.pageYOffset + document.querySelector(".projectsContainer").getBound

我试图将我的组件从react.component重构为hook,但遇到了一些麻烦。我真的不明白如何使用我的状态补偿。该值已设置,或者在需要时未设置

第一次尝试:

const [offsetTop, setOffsetTop] = useState();

useEffect(() => {
    setOffsetTop(window.pageYOffset + document.querySelector(".projectsContainer").getBoundingClientRect().top)
    console.log(offsetTop);
    window.addEventListener('scroll', handleScroll, true)
    return () => window.removeEventListener("scroll", handleScroll);
}, []);
我还尝试将它与第二个方法useEffect一起使用,并将[offsetTop]作为第二个参数,但我的日志显示了两次,其中包含unde和值。我理解为什么它显示了两次,但仍然不能解决我的问题,我的情况不起作用

第二次尝试:

const [offsetTop, setOffsetTop] = useState();

useEffect(() => {
    setOffsetTop(window.pageYOffset + document.querySelector(".projectsContainer").getBoundingClientRect().top)
}, []);

useEffect(() => {
    console.log(offsetTop);
    window.addEventListener('scroll', handleScroll, true)
    return () => window.removeEventListener("scroll", handleScroll);
}, [offsetTop]);
handleScroll功能:

功能手柄{ console.logoffsetTop; const scrolledY=window.scrollY 如果滚动Y>offsetTop console.logworks }
与第一次尝试相同的代码:放在componentDidMount{}中,使用它可以很好地工作。因此,情况并不坏。这是关于何时设置值以及useState和useEffect如何工作的问题。

您的条件在第一个变量中不起作用吗?这看起来是正确的,在这种情况下,console.logoffsetTop不应该打印新设置的值,而是之前设置的值。要按照您的意愿记录,您需要:

const[offsetTop,setOffsetTop]=useState; useEffect=>{ setOffsetTopwindow.pageYOffset+document.querySelector.projectsContainer.getBoundingClientRect.top window.addEventListener'scroll',handleScroll,真 return=>window.removeEventListenerscroll,handleScroll; }, []; useEffect=>{ console.logoffsetTop; },[offsetTop]; 第二次尝试的问题是它会执行以下操作:

第一次渲染: 第一次使用效果设置新的偏移 第二次使用效果火与旧的偏置 偏移更新导致重新渲染 第二个useEffect进行清理,删除事件侦听器 我猜,在这里的某个地方,浏览器传播事件,而你的听众不见了 第二次useEffect使用新的offsetTop再次激发,并再次设置侦听器,但它已经错过了事件 啊。。。那只是你问题的一部分

问题的第二部分是handleScroll有效地从创建偏移值并将其设置为侦听器的渲染周期捕获偏移值。应该使用useRef使handleScroll与当前值保持同步,如果出于其他原因不需要offsetTop,则根本不需要使用state。你可以做:

const{current:heap}=useRef{ 偏移量:0, }; useEffect=>{ 功能手柄{ console.logheap.offsetTop; const scrolledY=window.scrollY ifscrolledY>heap.offsetTop console.logworks } heap.offsetTop=window.pageYOffset+document.querySelector.projectscocontainer.getBoundingClientRect.top; window.addEventListener'scroll',handleScroll,真 return=>window.removeEventListenerscroll,handleScroll; //堆在重新渲染时保证为同一对象, //因此,将其包含在下面的依赖项中不会产生任何影响 //重新计算。但是,如果不包括它,请使用ESLint //为了检查代码错误,它会抱怨堆不存在 //作为缺少的依赖项。 },[heap];
这样,offsetTop在重新渲染时是持久的,handleScroll始终使用当前值。如果您还需要在offsetTop更新时重新渲染,那么您还可以使用useState触发重新渲染,例如,也可以将offsetTop值注入渲染组件。

这让我觉得您可能根本不需要状态。为什么不根据需要导出offsetTop的值

useEffect(() => {
  function handleScroll() {
    const scrolledY = window.scrollY;
    const offsetTop = window.pageYOffset + document.querySelector(".projectsContainer").getBoundingClientRect().top;
    if(scrolledY > offsetTop) console.log("works")
  }

  window.addEventListener('scroll', handleScroll, true)
  return () => window.removeEventListener("scroll", handleScroll, true);
}, []);
然而,也许你的想法是,你想要捕获offsetTop的初始值,然后在事情发生变化时使用它。在这种情况下,我认为您的主要问题是由于removeEventListener没有正确清理,因为您没有传递与addEventListener相同的参数missing true。因此,仍然有一个handleScroll实例保存第一次渲染的offsetTop的初始值,我认为这就是为什么您会看到未定义被记录的原因

错误的❌ 正当✅
复制:

您确定吗。当useEffect运行时,可以查询projectsContainer吗?为了确保它是正确的,您可以改为尝试,它在所有DOM变异后同步运行。您的右变体有这个问题:它在每次更新offsetTop时删除并重新添加事件侦听器,这在性能上是不好的,当删除前一个侦听器时,在这两个更新之间也会错过一些更新,但新的侦听器尚未添加。removeEventListener的参数很好。。必须与addEventListener的匹配..-我错过了:
useEffect(() => {
  setOffsetTop(window.pageYOffset +
      document.querySelector(".projectsContainer").getBoundingClientRect().top;);
}, []);

useEffect(() => {
  // The first time this useEffect runs, the value of `offsetTop`
  // is still the initial value of undefined.
  function handleScroll() {
    console.log(offsetTop)
    const scrolledY = window.scrollY;
    if (scrolledY > offsetTop) console.log("works");
  }

  window.addEventListener("scroll", handleScroll, true);
  // This doesn't get removed correctly
  // because you don't pass the same parameters (missing `true`)
  return () => window.removeEventListener("scroll", handleScroll); 
}, [offsetTop]);
useEffect(() => {
  setOffsetTop(window.pageYOffset +
      document.querySelector(".projectsContainer").getBoundingClientRect().top;);
}, []);

useEffect(() => {
  function handleScroll() {
    const scrolledY = window.scrollY;
    if (scrolledY > offsetTop) console.log("works");
  }

  window.addEventListener("scroll", handleScroll, true);
  return () => window.removeEventListener("scroll", handleScroll, true);
}, [offsetTop]);