I'm trying to make a progress bar that starts as the user scrolls to the right for a row of products for a sample e-commerce site. I've been getting a number of type errors to which I've made adjustments, but I'm now still getting the error "TypeError: Cannot read property 'addEventListener' of null" for line 12.
Please could someone provide assistance so it will work? (fyi pardon this code, still a bit of a React newbie). Thanks!
import React from 'react';
import { taskData } from "./cdg-data";
import ProgressBar from './progress';
class CDG extends React.Component {
state = {
scrollPosition: 0
}
listenToScrollEvent = () => {
const element = document.querySelector("CDG");
element.addEventListener("scroll", () => {
requestAnimationFrame(() => {
element.calculateScrollDistance();
});
});
}
calculateScrollDistance = () => {
const element = document.querySelector("CDG");
const pixels = element.scrollLeft; // CURRENT number of pixels scrolled by the user
const elementWidth = element.clientWidth; // width of just the element (no scrolling)
const fullElementWidth = element.scrollWidth; // full total distance of the element (with scrolling)
const totalScrollableDistance = fullElementWidth - elementWidth;
const scrollPosition = Math.floor(pixels / totalScrollableDistance * 100) // gets the percentage that the user has scrolled
element.setState({
scrollPosition,
})
}
componentDidMount() {
this.listenToScrollEvent();
}
render() {
return(
<div>
<h2 className="cdg-title">THE COLLECTION</h2>
<div className="CDG">
{taskData.map(item => {
return (
<div className="image-container">
<a href={item.url} target="_blank" rel="noreferrer">
<p className="title">{item.title}</p>
<p className="price">{item.price}</p>
</a>
<img className="cdg-image"
src={item.image}
alt="Converse"
/>
</div>
);
})}
</div>
<div className="Progress">
<ProgressBar scroll={this.state.scrollPosition + '%'}/>
</div>
</div>
);
}
}
export default CDG;
This is the final correct solution if anyone needs it:
import React from 'react';
import { taskData } from "./cdg-data";
import ProgressBar from './progress';
class CDG extends React.Component {
state = {
scrollPosition: 0
}
listenToScrollEvent = () => {
const element = document.querySelector(".CDG");
element.addEventListener("scroll", () => {
requestAnimationFrame(() => {
this.calculateScrollDistance();
});
});
}
calculateScrollDistance = () => {
const element = document.querySelector(".CDG");
const pixels = element.scrollLeft; // CURRENT number of pixels scrolled by the user
const elementWidth = element.clientWidth; // width of just the element (no scrolling)
const fullElementWidth = element.scrollWidth; // full total distance of the element (with scrolling)
const totalScrollableDistance = fullElementWidth - elementWidth;
const scrollPosition = Math.floor(pixels / totalScrollableDistance * 100) // gets the percentage that the user has scrolled
this.setState({
scrollPosition,
})
}
componentDidMount() {
this.listenToScrollEvent();
}
render() {
return(
<div>
<h2 className="cdg-title">THE COLLECTION</h2>
<div className="CDG">
{taskData.map(item => {
return (
<div className="image-container">
<a href={item.url} target="_blank" rel="noreferrer">
<p className="title">{item.title}</p>
<p className="price">{item.price}</p>
</a>
<img className="cdg-image"
src={item.image}
alt="Converse"
/>
</div>
);
})}
</div>
<div className="Progress">
<ProgressBar scroll={this.state.scrollPosition + '%'}/>
</div>
</div>
);
}
}
export default CDG;
import React from 'react';
const ProgressBar = (props) => {
const { scroll } = props;
const containerStyles = {
height: 5,
width: '33%',
backgroundColor: '#939191',
margin: '0 auto 50px',
}
const fillerStyles = {
height: '100%',
width: `${scroll}`, // dependent on JavaScript scroll, not the percentage completed as in the example
backgroundColor: '#A50209',
textAlign: 'center'
}
return (
<div style={containerStyles}>
<div style={fillerStyles}>
</div>
</div>
);
};
export default ProgressBar;