Skip to content

Instantly share code, notes, and snippets.

@jonshipman
Last active June 5, 2020 15:32
Show Gist options
  • Save jonshipman/d5de1a0471993454e02707d84fbdac3f to your computer and use it in GitHub Desktop.
Save jonshipman/d5de1a0471993454e02707d84fbdac3f to your computer and use it in GitHub Desktop.
Animate React Component
import React, { Component, createRef } from 'react';
class _sharedScrollHandler {
functions = []
attached = false;
constructor() {
this.boundHandler = this.handleScroll.bind(this);
this.addFun = this.add.bind(this);
this.removeFun = this.remove.bind(this);
}
attach() {
if (!this.attached) {
window.addEventListener('scroll', this.boundHandler, true);
this.attached = true;
}
}
detach() {
if (this.functions.length < 1) {
window.removeEventListener('scroll', this.boundHandler, true);
this.attached = false;
}
}
handleScroll() {
if (this.functions) {
this.functions.forEach(fn => {
fn({ width: document.documentElement.clientWidth, height: document.documentElement.clientHeight });
});
}
}
add(fn) {
this.functions.push(fn);
this.attach();
}
remove(fn) {
this.functions = this.functions.filter(f => f !== fn);
this.detach();
}
}
const sharedScrollHandler = new _sharedScrollHandler();
export default class extends Component {
state = {
inViewPort: false,
};
ref = createRef();
constructor(props) {
super(props);
this.handleScrollBound = this.handleScroll.bind(this);
}
componentDidMount() {
sharedScrollHandler.addFun(this.handleScrollBound);
}
componentWillUnmount() {
sharedScrollHandler.removeFun(this.handleScrollBound);
}
handleScroll({ height }) {
const ele = this.ref.current;
const boundingRect = ele.getBoundingClientRect();
if (boundingRect.top - height < 0) {
this.setState({ inViewPort: true });
} else {
this.setState({ inViewPort: false });
}
}
render() {
const { children, className, animate, ...rest } = this.props;
const { inViewPort } = this.state;
let c = className || '';
if (inViewPort) {
let a = (animate || 'fadeIn').split(' ');
a = a.map(_ => `animate__${_}`).join(' ');
c += ` animate__animated ${a}`;
}
return (
<div ref={this.ref} className={c} { ...rest }>
{children}
</div>
);
}
}
@jonshipman
Copy link
Author

Import 'animate.css' in npm/yarn and wrap your component with and pass the animate prop to have the component animate when entering the viewport.

<Animate animate="fadeIn infinite">Hello World</Animate>

Requires the animate.css css library. https://animate.style/

@jonshipman
Copy link
Author

Added a performance boost of a shared scroll event among all animate components.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment