Skip to content

Instantly share code, notes, and snippets.

@B-Stefan
Created March 30, 2015 11:59
Show Gist options
  • Save B-Stefan/ef800cd0f8b10597d5df to your computer and use it in GitHub Desktop.
Save B-Stefan/ef800cd0f8b10597d5df to your computer and use it in GitHub Desktop.
Alternative visibility sensor for react.js
/** @jsx React.DOM */
'use strict';
import React = require('react');
export interface VisibilitySensorProps{
active:boolean
delay: number
onChange(isVisible:boolean):void
children:any[] | string
}
class VisibilitySensorManager {
private allInstances:VisibilitySensor[] = [];
public addInstance(instance:VisibilitySensor){
this.allInstances.push(instance);
if(this.allInstances.length == 1){
this.startWatch()
}
}
public removeInstance(instance:VisibilitySensor){
var index = this.allInstances.indexOf(instance);
if (index > -1) {
this.allInstances.splice(index, 1);
}
if(this.allInstances.length == 0){
this.stopWatch()
}
}
private interval:any;
private startWatch(){
if (this.interval) {
return;
}
var self = this;
this.interval = setInterval(function(){
self.allInstances.forEach(function(item,index){
item.check.bind(item)()
})
}, VisibilitySensor.defaultProps.delay);
}
private stopWatch(){
this.interval = clearInterval(this.interval);
}
}
export class VisibilitySensor extends React.Component<VisibilitySensorProps,any,any> {
static defaultProps={
active: true,
delay: 200
};
private static manager = new VisibilitySensorManager();
private manager: VisibilitySensorManager = VisibilitySensor.manager;
private lastValue:any;
private interval: any;
constructor (props, context) {
super(props, context)
}
componentDidMount () {
if (this.props.active) {
this.manager.addInstance(this);
}
}
componentWillUnmount (){
this.manager.removeInstance(this);
}
componentWillReceiveProps(nextProps:VisibilitySensorProps) {
if (nextProps.active != this.props.active) {
if(nextProps.active){
this.lastValue = null;
this.manager.addInstance(this);
}else {
this.manager.removeInstance(this);
}
}
}
check () {
var el = React.findDOMNode(this);
var rect = el.getBoundingClientRect();
//Element is visible
if(this.lastValue == true){
var isVisible = (
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}else {
var isVisible = (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
// notify the parent when the value changes
if (this.lastValue !== isVisible) {
this.lastValue = isVisible;
this.props.onChange(isVisible);
}
}
render(){
return (
React.createElement('div', null, [this.props.children])
);
}
}
@B-Stefan
Copy link
Author

Based on React 0.13 and Typescript 1.5

Used with infinityScroll list Component to fade in elements that in the user viewport, based on:

https://github.com/joshwnj/react-visibility-sensor

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