In many applications, there are lists where there are items that you want to scroll to that are not visible, because there is an interaction that requires that content to be shown. With React it makes it easy to build out a reasonable component so that this could be used across your application.
Let's take a look at our code. We have an app and a div -- that's our scroller -- and we have some items that we are rendering inside there. If you look at the CSS we just have a width of 350 pixels on our app and we center it. Our scroller has a width and height and an overflow of auto. We just have enough items so that when the scrolled content expands past 300 pixels we will get that scroll bar.
To start, we're going to create a file called scroller.js. Inside of this we will create a new component that we'll just call scroll view. Then we'll also set up another component called scroll element. This will then wrap all the components and that we want to be able to scroll to.
Because we don't necessarily want to add any additional divs for our scroll view and we'll just use the scroll view that a user would add, we'll just return react.children.only.this.props.children.
The technique we will use will utilize context types. We need to go install the prop types npn module, which basically was extracted from the react module and put into its own package. That means we now need to input prop types from prop types.
Before we set up context we'll set up a few things so that we can pass them down on our context. The first will be our elements. Our elements will just be a class property on this particular instance that will hold the names and refs of our elements inside of our list that we want to scroll to.
We'll create a registered function and set it on this class as well as an unregistered function. Our registered function will take a name and a ref. This ref will be the reference to the scroll element child down below. Additionally, we will add a name here, so we know which item to unregister when a potential item in the list unmounts.
The registered function will just assign this.elementsname equal to the ref. Then in our unregister we'll just delete this.elementsname and clear it from our list. It's an element that we can't scroll to any more.
Now we need to set up our child context types. Because we're using class properties we can say static child context types, say scroll PTO. This is setting up any child that references this scroll on context will have access to whatever we register inside of our get child context function.
React will enforce proper return types because we've set an object here. So we need to then return an object on scroll and we'll say register, and then pass in this.register, and then unregister, and pass in this.unregister.
Now we need to set up our scroll element. Because we are referencing the scroll context we need to say static context types is equal to scroll PTO. That way it tells this element to grab the scroll context of its parent, which happens to be what we set up here.
Because we don't want to add any additional markup that might affect styling, we're just going to use the react.clone element function. This will then take this.props.children and allow us to add additional properties on.
What we're going to do is use the ref function to get access to the actual component instance or the div. We'll say ref is equal to a call back function, say this.element is equal to ref. Because we're using a call back syntax here, if any other thing up above were to use a call back ref this would still continue to work for them too. We would not override the ref property.
Now that we've set up scroll on our context types we can say component unmount and say this.context.scroll.register. We will let the outside world register the name that it wants. We'll say this.props.name, and then this.element.
Then because we don't want to keep track of elements that are unmounted we will say this.context.scroll.unregister, this.props.name inside of our component will unmount function. The only thing left to do is set up a scroll to function on our scroller. We'll say scroll to, and that will receive the name of the thing that we want to scroll to.
We now need to get access to the raw download so we can actually scroll to it. However, because we are using react.clone element, we don't necessarily know if the child is a div or if the child is another React component. We just need to use the find DOM node function. We'll pass in this.element's name. Then we need to now import, find DOM node from React DOM.
Additionally, because we don't necessarily want to reimplement scroll into view functionality, there is a plugin on the web called scroll into view. It has zero dependencies besides a request animation frame polyfills and allows us to simply pass in a DOM node and time and other configurations to scroll to that particular element within a particular list.
We'll go to our terminal and say yarn add scroll into view. We can come back to IDE and import scroll into view from scroll into view that we just installed. Back to our scroll to function, we'll say scroll into view, we'll pass in our node and some configuration.
We'll say time of 500 milliseconds and then we'll say align top zero. This will align the scroll to the top of the element. It defaults to 05, which is the center of the element, however we'll scroll to the top of it. Now this is ready to use.
We will now go import scroll view in our scroll element from scroller, which we've set up here. We'll need to use our scroll view to wrap our scroll list to thing that we had with the overflow auto.
Then additionally we need to wrap each individual item that we want to scroll to inside of our scroll element. We need to pass in our name so we have some data set up previously that has a name and an image.
To get access to the scroll to function that we've set up here we need to set up our ref, so we'll say ref, scroller, and it's a call back function, so it's this.scroller equals scroller. Then we'll set up a scroll to function here and say, this will receive a name and then we'll say this.scroller.scrolltothename.
Finally, we'll create a few buttons. We'll loop over each of our items and map them to buttons that will then call scroll to with the name. The other thing that we forgot to do is set up a default or an export for our scroll element. We need to say export scroll element.
Now we're ready to test it out in the browser. We have our list that we're rendering here, we have our buttons, and we can now click on any of the buttons, and it will animate to whatever position they are inside of our scrollable list.