Reputation: 77
I don't know why the handleScroll only executes once, not when i keep scrolling up and down. And I need to somehow get the element's height but im not sure how other than documentElement. The function needs to turn a true/false so that I can do a setState and add/change a class in my heroGallery div for a css animation.
import React, { Component } from "react";
class Intro extends Component {
constructor(props) {
super(props);
this.heroRef = React.createRef();
this.state = {};
}
componentDidMount = () => {
this.heroRef.current.getBoundingClientRect();
let hero2 = this.heroRef;
console.log(this.heroRef.current);
window.addEventListener("scroll", this.handleScroll(hero2));
};
componentWillUnmount = () => {
window.removeEventListener("scroll", this.handleScroll);
};
handleScroll = elm => {
var rect = elm.current.getBoundingClientRect();
//var viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight);
//return !(rect.bottom < 0 || rect.top - viewHeight >= 0);
};
render() {
return (
<div className="introCont">
<div className="introFirstSection" />
<div className="heroSection">
<div className="heroGallery" ref={this.heroRef}>
<div className="slide-down">item 1</div>
<div>item 2</div>
<div>item 3</div>
<div>item 4</div>
<div>item 5</div>
<div>item 6</div>
<div>item 7</div>
<div>item 8</div>
</div>
</div>
</div>
);
}
}
export default Intro;
EDIT: Taking out my intro component from Switch lets it work.
import React, { lazy, Suspense, Component } from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import { connect } from "react-redux";
import * as actions from "./actions";
//import asyncComponent from "./components/AsyncComponent";
//const Header = asyncComponent(() => import("./Header"));
import Intro from "./components/Intro";
const Header = lazy(() => import("./components/Header"));
const Footer = lazy(() => import("./components/Footer"));
const Landing = lazy(() => import("./components/Landing"));
const Profile = lazy(() => import("./components/Profile"));
const BookList = lazy(() => import("./components/books/BookList"));
const BookNote = lazy(() => import("./components/books/BookNote"));
const StatsChart = lazy(() => import("./components/StatsChart"));
class App extends Component {
componentDidMount() {
this.props.fetchUser();
}
render() {
return (
<BrowserRouter>
<div className="rootdk">
<Suspense fallback={<div />}>
<Header />
</Suspense>
<div className="container">
<Suspense fallback={<div className="loader" />}>
<Switch>
<Route exact path="/intro" component={() => <Intro />} />
<Route
exact
path="/mybooks"
component={() =>
this.props.thisuser ? <BookList /> : <Landing />
}
/>
<Route
exact
path="/booknotes"
component={() =>
this.props.thisuser ? <BookNote /> : <Landing />
}
/>
<Route
exact
path="/statschart"
component={() =>
this.props.thisuser ? <StatsChart /> : <Landing />
}
/>
<Route
exact
path="/profile"
component={() =>
this.props.thisuser ? <Profile /> : <Landing />
}
/>
<Route exact path="/" component={Landing} />
</Switch>
</Suspense>
<Suspense fallback={<div />}>
<Footer />
</Suspense>
</div>
</div>
</BrowserRouter>
);
}
}
function mapStateToProps(props) {
return { thisuser: props.auth };
}
export default connect(
mapStateToProps,
actions
)(App);
Upvotes: 0
Views: 1023
Reputation: 77
Another answer would be to use the HTML5 API, which makes it much much easier: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
Also, the container obviously has to have a fixed height, and have the overflow property set to auto or scroll.
Example:
import React, { Component } from "react";
import ReactDOM from "react-dom";
class Intro extends Component {
constructor(props) {
super(props);
this.heroRef = React.createRef();
this.state = {
heroanim: "no"
};
}
componentDidMount = () => {
setTimeout(() => {
this.startup();
}, 500);
this.startup();
};
componentWillUnmount = () => {};
startup = () => {
//the class we want to observe for visibility changes, scrolling for animation.
let adBox = document.querySelector(".heroSection");
//checks if page was tabbed out or hidden. separate from intersectionobserver
document.addEventListener(
"visibilitychange",
this.handleVisibilityChange,
false
);
//intersectionobserveroptions. root is highest element you want to compare to. threshhold is % visibility of element you're comparing to root. 'callback activated when 50% visibility.'
let observerOptions = {
root: null,
rootMargin: "0px",
threshold: [0.7]
};
//create new intersection observer
let adObserver = new IntersectionObserver(
this.intersectionCallback,
observerOptions
);
//call it.
adObserver.observe(adBox);
};
handleVisibilityChange = () => {
if (document.hidden) {
//changeclass to no animate through setstate
} else {
//changeclass to animate
}
};
intersectionCallback = entries => {
entries.forEach(entry => {
let adBox = entry.target;
if (entry.isIntersecting) {
this.setState({ heroanim: "yes" });
} else {
console.log("not");
this.setState({ heroanim: "no" });
}
});
};
render() {
return (
<div className="introCont">
<div className="introFirstSection" />
<div
className={
this.state.heroanim === "yes"
? "heroSection heroAnim"
: "heroSection"
}
ref={this.heroRef}
>
<div className="heroGallery">
<div className="slide-down">item 1</div>
<div>item 2</div>
<div>item 3</div>
<div>item 4</div>
<div>item 5</div>
<div>item 6</div>
<div>item 7</div>
<div>item 8</div>
</div>
</div>
</div>
);
}
}
export default Intro;
Upvotes: 0
Reputation: 725
It is because you are invoking the method in your addEventListener
.
Demo: https://codesandbox.io/s/nv16oq6j?fontsize=14
Change your componentDidMount
function to this.
componentDidMount = () => {
this.heroRef.current.getBoundingClientRect();
let hero2 = this.heroRef;
console.log(this.heroRef.current);
window.addEventListener("scroll", () => this.handleScroll(hero2));
};
All I did is make the second argument of addEventListener
as a function.
Upvotes: 3