Scrolling by Dragging React.js reusable component
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: