Skip to content

Instantly share code, notes, and snippets.

@danilowoz
Created December 20, 2018 17:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danilowoz/71e303f6b2c73672ca247e818af3f689 to your computer and use it in GitHub Desktop.
Save danilowoz/71e303f6b2c73672ca247e818af3f689 to your computer and use it in GitHub Desktop.
import * as React from 'react'
interface IState {
offSet: number
}
interface IProp {
force?: number
offsetComp?: number
children(offSet: number): React.ReactNode
}
export default class RenderParallax<P extends IProp> extends React.Component<
P,
IState
> {
static defaultProps = {
force: 1,
}
state = { offSet: 0 }
lastScrollY: number = 0
ticking: boolean = false
private wrapper = React.createRef<HTMLDivElement>()
private currentBounding: null | ClientRect = null
private bodyBounding: null | ClientRect = null
componentDidMount() {
this.currentBounding = this.wrapper.current!.getBoundingClientRect()
this.bodyBounding = document.body.getBoundingClientRect()
window.addEventListener('scroll', this.requestAnimation)
}
componentWillUnmount() {
window.removeEventListener('scroll', this.requestAnimation)
}
requestAnimation = () => {
if (!this.ticking) {
window.requestAnimationFrame(this.animation)
this.lastScrollY = window.scrollY
this.ticking = true
}
}
isDesktop = () => {
return window.innerWidth >= 832 // 52em * 16px
}
animation = () => {
if (!this.isDesktop()) {
return this.setState({ offSet: 0 })
}
const elementOffset = this.currentBounding!.top - this.bodyBounding!.top
const threshold = 10 / this.props.force! || 1
const offSet =
(this.lastScrollY - elementOffset * 0.8) / threshold +
(this.props.offsetComp! || 0)
this.setState({ offSet })
this.ticking = false
}
render() {
return (
<div ref={this.wrapper}>{this.props.children(this.state.offSet)}</div>
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment