【问题标题】:React Hook State not matchingReact Hook 状态不匹配
【发布时间】:2020-10-22 16:40:16
【问题描述】:

我创建了一个自定义挂钩来监控滚动行为。但是当我从使用钩子的组件中更改状态时,我确实从控制台日志中看到了状态更改,但是一旦我开始滚动,状态的原始值为 true。更奇怪的是react dev工具和console log输出的内容不匹配。

import React, { useEffect } from 'react';
import useExample from './useExample';


function Example() {
  const [status, setStatus] = useExample();
  console.log(`example, status: ${status}`);


  useEffect(() => {
    setStatus(false);
  },[]);

  useEffect(() => {
    setInterval(() => console.log(status), 2000);
  }, [])

  return (<div>
    Something scrollable
    ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
    ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
    ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
    ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
    ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
    ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
    ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
    ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
    ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
  </div>);

}

export default Example;
import React, { useState, useEffect } from 'react';

const useExample = () => {
  const [status, setStatus] = useState(true);
  console.log(`useExample status: ${status}`);
  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  function handleScroll() {
    console.log(`handle scroll, status: ${status}`);
  }

  return [status, setStatus];
};

export default useExample;

我更新了功能。 setInterval 函数始终返回 true,即使在 Example.js 中的第一个 useEffect 中更改了状态。 React dev tools console log

更新 如果我将其更改为此它会起作用,我相信问题与事件侦听器的状态范围有关。它需要被移除并更新为正确的状态。

import React, { useState, useEffect, useCa } from 'react';

const useExample = () => {
  const [status, setStatus] = useState(true);
  console.log(`useExample status: ${status}`);
  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, [status]);

  useEffect(() => {
    console.log(`${status} useffect`);
  }, [status]);

  function handleScroll() {
    console.log(`handle scroll, status: ${status}`);
  }

  return [status, setStatus];
};

export default useExample;

【问题讨论】:

  • 为什么要把事件监听器写在另一个组件中,而不是在同一个组件中。
  • 需要复用组件

标签: reactjs react-hooks use-state


【解决方案1】:

您在示例中没有正确导出您的函数,但是您在父组件上导入了它们,您在子组件上使用 useState,如果您想将该函数作为子组件分离,则状态应该在父组件中,并且将它导入到您的状态最初设置为 true 的孩子中,您的 useExample 将始终返回 true。

export const useExample = (status) => {

  console.log(`useExample status: ${status}`);

  function handleScroll() {
    console.log(`handle scroll, status: ${status}`);
  }

  useEffect(() => {
     window.addEventListener('scroll', handleScroll);
     return () => window.removeEventListener('scroll', handleScroll);
  }, []);

};

在父级中应该是

import {useExample} from './useExample';

useExample(status);

但是由于函数内部是 useEffect ,因此您可以在父组件中这样编写它。这样做会更容易。

import React, { useState, useEffect } from 'react';

function Example() {
   const [status, setStatus] = useState(true);


   function handleScroll() {
     console.log(`handle scroll, status: ${status}`);
   }

   useEffect(() => {
     window.addEventListener('scroll', handleScroll);
     return () => window.removeEventListener('scroll', handleScroll);
   }, []);


   useEffect(() => {
     setStatus(false);
   },[]);

   useEffect(() => {
     setInterval(() => console.log(status), 2000);
   }, [])

   return (<div>
     Something scrollable
      ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
      ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
      ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
      ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
      ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
      ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
      ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
      ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
      ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
   </div>);

}

export default Example;

【讨论】:

  • 但我从 useExample 返回 [status, setStatus] 而不是 {status, setStatus}
  • 我更新了我的答案,看看这是否可行。不过我还没有测试过
  • 嗯,不确定,所以我看到了问题,我正在使用事件侦听器,如果使用挂钩,则需要重新安装,
  • 还试图重用滚动逻辑,所以我需要在单独的钩子中使用它
猜你喜欢
  • 2021-08-24
  • 1970-01-01
  • 1970-01-01
  • 2020-12-19
  • 2020-03-03
  • 1970-01-01
  • 2023-03-21
  • 2020-08-23
  • 2021-04-16
相关资源
最近更新 更多