Scrolling by Dragging React.js reusable component

Eyas Mattar
3 min readJun 3, 2019

--

We are going to create a reusable React.js Scroll by Drag component

One of the best approaches to implement a reusable component is, at first, to use it.

When we imagine and try to use the component the way we want, mostly we will get a better structure and design in our head.

Consider we have a timeline component where we want to scroll left and right by dragging the <div> element clicked anywhere.

import React from 'react';
import classNames from 'classnames';
import PropTypes from 'prop-types';

export class Timeline extends React.PureComponent {

render() {
const {
classes,
data,
} = this.props;
return (
<div ref={this.ref}>
<Timeline
data={data}
/>
</div>
);
}
}

Timeline.propTypes = {
data: PropTypes.array,
};

export default Timeline;

We would like that the ROOT <div> to be scrollable.

We can reach that by creating a HOC (High Order Component) that will wrap the desired component and will provide the scroll functionality despite of the component children type.

Creating ScrollDrag component

We will create a one way drag (horizontally).

in the same exact way you can extend to do both ways (clientX, clientY)

import React from 'react';
import PropTypes from 'prop-types';

export class ScrollDrag extends React.Component {
constructor(props) {
super(props);
this.ref = React.createRef();
this.state = {
isScrolling: false,
clientX: 0,
scrollX: 0,
};
}

onMouseDown = e => {
this.setState({ ...this.state, isScrolling: true,
clientX: e.clientX });
};

onMouseUp = () => {
this.setState({ ...this.state, isScrolling: false });
};

onMouseMove = e => {
const { clientX, scrollX } = this.state;
if (this.state.isScrolling) {
this.ref.current.scrollLeft = scrollX + e.clientX - clientX;
this.state.scrollX = scrollX + e.clientX - clientX;
this.state.clientX = e.clientX;
}
};

render() {
const { ref, rootClass } = this.props;
return (
<div
ref={ref}
onMouseDown={this.onMouseDown}
onMouseUp={this.onMouseUp}
onMouseMove={this.onMouseMove}
className={rootClass}
>
{React.Children.map(this.props.children, child =>
React.Children.only(child))}
</div>
);
}
}

ScrollDrag.defaultProps = {
ref: { current: {} },
rootClass: '',
};

ScrollDrag.propTypes = {
ref: PropTypes.object,
rootClass: PropTypes.string,
children: PropTypes.string,
};

export default ScrollDrag;

Note that the children should be wider than the screen in able to see the results

Let’s examine the state object:

isScrolling

is used to toggle ON/OFF the scroll

Webpack 5: Complete Developers Guide

clientX

stores the mouse initial pointer when we click to drag, so we can calculate

scrollX

stores the current scroll position so we can append to it every time we move the mouse

Full Advanced React Course on Udemy

Here described the UX flow:

--

--

Responses (3)