简体   繁体   English

反应中的自定义钩子性能问题

[英]custom hook performance issues in react

I have re-written this javascript code logic to a react custom hook to use.我已将此 javascript 代码逻辑重写为要使用的反应自定义挂钩。

But it seems like the solution i have made is a bit slow, and heavy on performance, I was wondering in which sort of ways I could make it more performant.但似乎我所做的解决方案有点慢,而且性能很重,我想知道我可以通过哪种方式使其性能更高。

This is the custom hook:这是自定义钩子:

import { useEffect, useState } from 'react';
import { isBrowser } from '@utils/environment';
import { NAVBAR_HEIGHT_PX } from '@common/helpers';

export const useSticky = stickyElement => {
  const [offset, setOffset] = useState(NAVBAR_HEIGHT_PX);
  let offsetTop = NAVBAR_HEIGHT_PX;
  let currPos = isBrowser ? window.pageYOffset : 0;
  let endScroll = isBrowser ? window.innerHeight - stickyElement?.current?.offsetHeight - 500 : 0;

  useEffect(() => {
    if (!isBrowser) {
      return undefined;
    }

    const positionStickySidebar = () => {
      const { innerHeight, scrollY } = window;

      endScroll = innerHeight - stickyElement.current.offsetHeight;

      if (window.scrollY < currPos) {
        if (offsetTop < NAVBAR_HEIGHT_PX * 2) {
          offsetTop = offsetTop + currPos - scrollY;
        } else if (offsetTop >= NAVBAR_HEIGHT_PX * 2 && offsetTop !== endScroll) {
          offsetTop = NAVBAR_HEIGHT_PX * 2;
        }
      } else {
        if (offsetTop > endScroll) {
          offsetTop = offsetTop + currPos - scrollY;
        } else if (offsetTop < (endScroll) && offsetTop !== endScroll) {
          offsetTop = endScroll;
        }
      }
      setOffset(offsetTop);
      currPos = window.scrollY;
    };

    window.addEventListener('resize', positionStickySidebar, {
      capture: false,
      passive: true,
    });
    window.addEventListener('scroll', positionStickySidebar, {
      capture: false,
      passive: true,
    });

    return () => {
      window.removeEventListener('scroll', positionStickySidebar);
      window.removeEventListener('resize', positionStickySidebar);
    };
  }, []);

  return offset;
};

This is the usage of it这是它的用法

const divRef = useRef(null);
const offsetTop = useSticky(divRef);

  <ContentContainer offsetTop={offsetTop} ref={divRef}>

And this is the styled component:这是样式化的组件:

export const ContentContainer = styled.div`
  position: sticky;
  top: ${({ offsetTop }) => `${offsetTop}px`};
`;

I would suggest two things:我建议两件事:

  1. Move all variables (except useState) inside useCallback function.在 useCallback function 中移动所有变量(除了 useState)。 This way on each render these values will not be recalculated.这种方式在每次渲染时不会重新计算这些值。 Especially that important for endScroll variable, because it uses offsetHeight in calculations.对于endScroll变量尤其重要,因为它在计算中使用offsetHeight Each invocation of offsetHeight causes reflow process in browser, which impacts performance a lot.每次调用offsetHeight都会导致浏览器中的回流过程,这对性能影响很大。 So calling it on each render is not something very good, especially in your case where such calculations doesn't affect anything (except on first render).因此,在每次渲染时调用它并不是一件好事,尤其是在这种计算不会影响任何事情的情况下(第一次渲染除外)。
  // Instead of this:
  export const useSticky = stickyElement => {
    // ...
    let offsetTop = NAVBAR_HEIGHT_PX;
    let currPos = isBrowser ? window.pageYOffset : 0;
    let endScroll = isBrowser ? window.innerHeight - stickyElement?.current?.offsetHeight - 500 : 0;
    // ...
  }


  // Do this:
  export const useSticky = stickyElement => {
    // ...
    useEffect(() => {
      if (!isBrowser) return undefined;
      let offsetTop = NAVBAR_HEIGHT_PX;
      let currPos = isBrowser ? window.pageYOffset : 0;
      let endScroll = isBrowser ? window.innerHeight - stickyElement?.current?.offsetHeight - 500 : 0;
      const positionStickySidebar = () => {
    // ...
  }
  1. Get rid of offset state ( const [offset, setOffset] =... ) if possible.如果可能,摆脱偏移量 state ( const [offset, setOffset] =... )。 Performance should become much better if you replace如果更换,性能应该会好得多
const [offset, setOffset] = useState(NAVBAR_HEIGHT_PX);
// ...
setOffset(offsetTop);
// ...
return offsetTop;

with

const topOffsetRef = useRef(NAVBAR_HEIGHT_PX);
// ...
stickyElement.current.style.top = offsetTop + 'px';
topOffsetRef.current = offsetTop;
// ...
return topOffsetRef.current;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM