使用useRef在React Hooks中恢复滚动位置不稳定

时间:2019-07-29 13:25:06

标签: javascript reactjs react-hooks

我想通过在useEffect内将窗口位置设置回其先前状态来滚动到我先前的窗口位置。为了获得以前的状态,我正在使用useRef。

该组件曾经是基于类的,因此可以完美地工作。在将其重构为钩子之后,这种“不稳定”的行为开始了。

在开始处声明useRef

const scrollRef = useRef(window.pageYOffset);

每当重新渲染组件时:

scrollRef.current = window.pageYOffset;

状态更新时:

useEffect(() => {
  window.scrollTo(0, scrollRef.current)
});

完整代码:

export default () => {
   const scrollRef = useRef(window.pageYOffset);
   ...
   scrollRef.current = window.pageYOffset;
   useEffect(() => {
      window.scrollTo(0, scrollRef.current)
   });

   return (
      ...
   );
}

在状态更新时,我想通过不具有这种“不稳定”的行为来变回到先前的窗口位置。 (通过摇晃,我的意思是看起来他滚动到顶部,然后又滚动到先前的位置,所以看起来好像在晃动)

2 个答案:

答案 0 :(得分:0)

您的问题的解决方案如下所示:

sandbox

首先创建一个自定义usePrevious挂钩。这只是另一个函数,它使用新的useRef方法存储以前的滚动值,并且仅在将新值传递给它时才对其进行更新。

// Hook
function usePrevious(value) {
  // The ref object is a generic container whose current property is mutable ...
  // ... and can hold any value, similar to an instance property on a class
  const ref = useRef();
  
  // Store current value in ref
  useEffect(() => {
    ref.current = value;
  }, [value]); // Only re-run if value changes
  
  // Return previous value (happens before update in useEffect above)
  return ref.current;
}

在实际组件中,我们声明一个previousPosition变量。每次重新渲染组件时,都会使用当前位置执行我们的customHook。它返回之前的位置,然后将其分配。

对于每个渲染,也将执行useEffect方法,因为我们没有将Array作为第二个参数传递。在那里,我们只是将当前滚动位置与 前一个,然后滚动回前一个,以防更改。

function Scroll(props){
  const prevPosition = usePrevious(window.pageYOffset);
   // Update scoll position with each update
   useEffect(() => {
     if(window.pageYOffset !== prevPosition){
         window.scrollTo(0, prevPosition);
     }  
   });

   return (
      <div>
      ...
      </div>
   );
}

答案 1 :(得分:0)

如果我理解正确,请使用useLayoutEffect代替useEffect。在呈现组件之前,它将滚动回到顶部。记住要添加依赖项数组。