React Hooks:即使状态没有改变,也要重新渲染

时间:2019-09-30 20:33:49

标签: reactjs react-hooks

我正在尝试实现一个简单的Header组件,该标题在到达某个滚动位置后将隐藏。

我想出了以下解决方案,并认为仅当Header的值实际发生变化(这不是正在发生的情况)时,才会重新呈现headerState组件。即使滚动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>
  )
};

2 个答案:

答案 0 :(得分:1)

重新渲染确实是由于useWindowScroll引起的。 如source所示,每次窗口滚动时,useWindowScroll都会调用setState。

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

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

  const frame = useRef(0);
  useEffect(() => {
    const handler = () => {
      cancelAnimationFrame(frame.current);
      frame.current = requestAnimationFrame(() => {
        if (window.pageYOffset > 50 && headerState !== 1) {
          setHeaderState(1);
        }
      });
    };

    window.addEventListener("scroll", handler, {
      capture: false,
      passive: true
    });

    return () => {
      cancelAnimationFrame(frame.current);
      window.removeEventListener("scroll", handler);
    };
  });

  return headerState;
};

答案 1 :(得分:0)

您说的问题是,内部%hhu可能会自行调用unsigned char *钩子来调用useWindowScroll

通常,组件重新渲染应该不是问题吗?这有问题吗?

但是,一种选择是将setState钩移到父级,然后使用React.memo来记住useState,并且仅在道具发生更改时才重新渲染。

useHeaderState