Reactjs React Hooks:即使状态没有改变,也要重新加载

Reactjs React Hooks:即使状态没有改变,也要重新加载,reactjs,react-hooks,Reactjs,React Hooks,我试图实现一个简单的标题组件,其中标题在到达某个滚动位置后会隐藏 我提出了下面的解决方案,并认为只有当headerState的值实际发生变化时,才会发生Header组件的重新渲染,而实际情况并非如此。即使未调用setHeaderState,组件也会在每次更改滚动位置时重新启动 我错过了什么?它是否因为我使用useWindowScroll而重新招标,我能以某种方式避免吗 import { useWindowScroll } from "react-use"; const useHeaderSt

我试图实现一个简单的标题组件,其中标题在到达某个滚动位置后会隐藏

我提出了下面的解决方案,并认为只有当headerState的值实际发生变化时,才会发生Header组件的重新渲染,而实际情况并非如此。即使未调用setHeaderState,组件也会在每次更改滚动位置时重新启动

我错过了什么?它是否因为我使用useWindowScroll而重新招标,我能以某种方式避免吗

 import { useWindowScroll } from "react-use";

const useHeaderState = () => {
  const [ headerState, setHeaderState ] = React.useState(0);

  const { y } = useWindowScroll();

  React.useEffect(() => {
    if (y > 50 && headerState !== 1) {
      setHeaderState(1);
    }
  }, [y, headerState]);

  return headerState;
}

const Header: React.FC = () => {
  const headerState = useHeaderState();

  console.log("rerender");

  return (
    <header
      className={cn(
        "fixed top-0 left-0 w-full text-white z-30 transition-transform transition-250",
        headerState === 1 && "-translate-16",
      )}
    >
      <div className="bg-gray-900 h-16 md:h-32">header</div>
    </header>
  )
};

正如您所说的问题是,useWindowScroll内部很可能在自己的useState钩子上调用setState

通常,组件重新呈现不应该是一个问题?这有什么问题吗

但是,一个选项是将useHeaderState钩子移动到父对象,然后使用以记忆标题,并且仅在道具已更改时重新渲染

从React导入*作为React; 从react-dom导入{render}; 从react use导入{useWindowScroll}; 常量useHeaderState==>{ 常量[headerState,setHeaderState]=React.useState0; const{y}=useWindowScroll; React.useffect=>{ 如果y>50&&headerState!==1{ setHeaderState1; } },[y,headerState]; 返回headerState; }; 常量标题:React.FC=React.memoprops=>{ console.logrerender; 回来 标题 ; }; 功能应用程序{ const headerState=useHeaderState; 回来 ; } const rootElement=document.getElementByIdroot; 渲染,根元素;
重新渲染确实是因为useWindowScroll。 如中所示,每次窗口滚动时,useWindowScroll都会调用setState

为了避免浪费渲染,您可以自己监听窗口滚动,而不是使用useWindowScroll,如:

常量useHeaderState==>{ 常量[headerState,setHeaderState]=React.useState0; const frame=useRef0; useEffect=>{ 常量处理程序==>{ 取消AnimationFrameFrame.current; frame.current=requestAnimationFrame=>{ 如果window.pageYOffset>50&&headerState!==1{ setHeaderState1; } }; }; window.addEventListenerscroll,处理程序{ 捕获:错误, 被动:对 }; 返回=>{ 取消AnimationFrameFrame.current; window.removeEventListenerscroll,处理程序; }; }; 返回headerState; };
这会让我的应用程序组件在每次滚动位置改变时都重新运行,不是吗?一般来说,我只是尽量避免不必要的重播。一个简单的标题可能不会对性能产生太大的影响,但随着我的应用程序变得越来越复杂,它可能会吗?我想在我的示例中,直接使用windowscroll事件而不是使用另一个钩子可能是最简单的。我只是认为我的Header组件只有在headerState值更改时才会重新渲染,但显然这不是它的工作方式,我不会过早地进行优化。我会保持简单。引入复杂性不可避免地会反过来咬你。React.memo仅用于存在明显性能问题的情况。相反,我不会担心这种不必要的重新渲染,除非您注意到性能问题,并使用React DevTools或browser DevTools对其进行测量,并指出原因并优化该问题。我认为这是一个很好的关于这个话题的概述: