I want to scroll to my previous window position by setting inside a useEffect the window position back to its previous state. To get the previous state, I am using useRef.
The Component was once class-based and there it worked perfectly. After I refactored it to hooks, this "shaky" behavior started.
Declaring the useRef
right at the beginning
const scrollRef = useRef(window.pageYOffset);
Whenever the ponent re-renders:
scrollRef.current = window.pageYOffset;
When the state gets updated:
useEffect(() => {
window.scrollTo(0, scrollRef.current)
});
The Complete Code:
export default () => {
const scrollRef = useRef(window.pageYOffset);
...
scrollRef.current = window.pageYOffset;
useEffect(() => {
window.scrollTo(0, scrollRef.current)
});
return (
...
);
}
On state update, I want to change back to the previous window position by not having this "shaky" behavior. (By shaky I mean it looks like he scrolls to the top and right after to the previous position so it looks like it shakes)
I want to scroll to my previous window position by setting inside a useEffect the window position back to its previous state. To get the previous state, I am using useRef.
The Component was once class-based and there it worked perfectly. After I refactored it to hooks, this "shaky" behavior started.
Declaring the useRef
right at the beginning
const scrollRef = useRef(window.pageYOffset);
Whenever the ponent re-renders:
scrollRef.current = window.pageYOffset;
When the state gets updated:
useEffect(() => {
window.scrollTo(0, scrollRef.current)
});
The Complete Code:
export default () => {
const scrollRef = useRef(window.pageYOffset);
...
scrollRef.current = window.pageYOffset;
useEffect(() => {
window.scrollTo(0, scrollRef.current)
});
return (
...
);
}
On state update, I want to change back to the previous window position by not having this "shaky" behavior. (By shaky I mean it looks like he scrolls to the top and right after to the previous position so it looks like it shakes)
Share Improve this question edited Jul 29, 2019 at 13:48 Dennis Vash 54k12 gold badges117 silver badges132 bronze badges asked Jul 29, 2019 at 13:25 EmreEmre 1531 gold badge2 silver badges10 bronze badges 1- Try adding a sandbox – Dennis Vash Commented Jul 29, 2019 at 15:04
2 Answers
Reset to default 1The solution to your problem could look as follows:
sandbox
First create a custom usePrevious
hook. This is just another function which uses the new useRef
method to store the previous scroll value and only updates it when a new value is passed to it.
// 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;
}
In the actual ponent we declare a previousPosition
variable. Every time the ponent re-renders, the our customHook is executed with the current position. It returns the previous position which then gets assigned.
Also with each render, the useEffect
method is being executed, as we do not pass an Array as second argument. There we just pare the current scroll position with
the previous and scroll back to the previous in case it changed.
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>
);
}
If I understand correctly, use useLayoutEffect
instead of useEffect
. This will scroll back to the top before the ponent is rendered. Remember to add the dependency array.