Reputation: 33
I have components which have dropdown. When dropdown is opened, I need to bring the scroll to the center if scroll occurs.
Details: https://codesandbox.io/s/modern-pine-k2dzx?file=/src/App.js
Upvotes: 0
Views: 697
Reputation: 1953
I have taken a stab with the following assumptions
The interesting part with this siutation, is requiring the ref to actually determine and set the scroll top position, which is only available after show is true, and the component has mounted. Assigning a ref value wont cause the component to rerender, so we need to add a callback which will provide us with a ref, and provide us with a concrete way to interact with the ref as soon as its available.
for this purpose, I created a function as follows
const refAssignCallback = (ref) => {
if (!containerRef.current && ref) {
//the containerRef is currently null, ref available = mounted.
containerRef.current = ref;
var element = containerRef.current;
var scrollHeight = element.scrollHeight;
var clientHeight = element.getBoundingClientRect().height;
//explicitly set the scrollTop position of the scrollContainer
containerRef.current.scrollTop = (scrollHeight - clientHeight) / 2;
} else {
//otherwise just assign/unassigned
containerRef.current = ref;
}
};
this function is assigned to the ref attribute of your scroll container div. When it mounts, a ref is provided to this function and we can react appropriately.
it first checks to see if the containerRef is currently null, because then we know its opening for the first time and we only want to programatically set the scroll position the first time it opens, and not again. Any other time we can just assign the containerRef to the recieved ref.
once we have the ref, we programatically set the scrollTop position of the scrollContainer to the half way position.
Full code below:
import React, { useRef, useState, useEffect } from "react";
import "./styles.css";
const App = () => {
const containerRef = useRef();
const [isOpen, setIsOpen] = useState(false);
//fired when the box is mounted
const refAssignCallback = (ref) => {
if (!containerRef.current) {
containerRef.current = ref;
var element = containerRef.current;
var scrollHeight = element.scrollHeight;
var clientHeight = element.getBoundingClientRect().height;
containerRef.current.scrollTop = (scrollHeight - clientHeight) / 2;
} else {
//otherwise just assign/unassign
containerRef.current = ref;
}
};
return (
<div className="App">
<button onClick={() => setIsOpen(!isOpen)}>HEY</button>
{isOpen && (
<div
ref={refAssignCallback}
style={{ height: "300px", overflowY: "auto" }}
name="scrollContainer"
>
<div
style={{
width: 300,
height: 1500,
backgroundColor: "lightGray",
marginTop: 20
}}
/>
</div>
)}
</div>
);
};
export default App;
Upvotes: 1