Repository URL to install this package:
|
Version:
1.0.1 ▾
|
import * as React from 'react'
import { findDOMNode } from 'react-dom'
import { createObserver, observeElement, unobserveElement } from './observer'
import { isDOMTypeElement, shallowCompare } from './utils'
import { IntersectionObserverProps } from './typings'
const observerOptions = ['root', 'rootMargin', 'threshold']
const observerProps = ['disabled'].concat(observerOptions)
const objectProto = Object.prototype
class IntersectionObserverComponent extends React.Component<IntersectionObserverProps> {
static displayName = 'IntersectionObserver'
get options() {
return observerOptions.reduce((options, key) => {
// tslint:disable:align
if (objectProto.hasOwnProperty.call(this.props, key)) {
const useQuery =
key === 'root' &&
objectProto.toString.call(this.props[key]) === '[object String]'
options[key] = useQuery
? document.querySelector(this.props[key])
: this.props[key]
}
return options
}, {})
}
handleChange = (event: React.ChangeEvent<any> | IntersectionObserverEntry) => {
this.props.onChange(event, this.unobserve)
if (this.props.onlyOnce) {
// eslint-disable-next-line no-undef
if (process.env.NODE_ENV !== 'production') {
if ('isIntersecting' in event) {
console.error(
`deprecation: onlyOnce requires isIntersecting to exists in IntersectionObserverEntry's prototype. Either your browser or your polyfill lacks support.`
)
}
}
if ((event as any).isIntersecting) {
this.unobserve()
}
}
// eslint-disable-next-line no-undef
if (process.env.NODE_ENV !== 'production') {
console.warn(
!this.props.hasOwnProperty('onlyOnce'),
'ReactIntersectionObserver: [deprecation] Use the second argument of onChange to unobserve a target instead of onlyOnce. This prop will be removed in the next major version.'
)
}
}
target: Element
renderedTarget: Element
targetChanged: boolean
observer: IntersectionObserver
/**
* @todo forwardRef........ !!!
*/
handleNode = (target: HTMLElement) => {
/**
* Forward hijacked ref to user.
*/
const nodeRef = (this.props.children as any).ref
if (nodeRef) {
if (typeof nodeRef === 'function') {
nodeRef(target)
} else if (typeof nodeRef === 'object') {
nodeRef.current = target
}
}
/**
* This is a bit ugly: would like to use getSnapshotBeforeUpdate(), but we do not want to depend on
* react-lifecycles-compat to support React versions prior to 16.3 as this extra boolean gets the job done.
*/
this.targetChanged =
(this.renderedTarget && target) != null && this.renderedTarget !== target
if (this.targetChanged) {
this.unobserve()
}
this.target = target
}
observe = () => {
this.target = (
isDOMTypeElement(this.target)
? this.target
: findDOMNode(this.target)
) as HTMLElement
this.observer = createObserver(this.options)
observeElement(this)
}
unobserve = () => {
if (this.target != null) {
unobserveElement(this)
}
}
componentDidMount() {
if (!this.props.disabled) {
this.observe()
}
}
componentDidUpdate(prevProps: {[key: string]: unknown}) {
const propsChanged = observerProps.some(prop =>
shallowCompare(this.props[prop], prevProps[prop])
)
if (propsChanged) {
this.unobserve()
}
if (this.targetChanged || propsChanged) {
if (!this.props.disabled) {
this.observe()
}
}
}
componentWillUnmount() {
this.unobserve()
}
render() {
// this value is null on the first render
this.renderedTarget = this.target
// @todo, not React.Children.Only?
return React.cloneElement(React.Children.only(this.props.children), {
ref: this.handleNode,
})
}
}
export { IntersectionObserverComponent }
export default IntersectionObserverComponent