-
-
Save norbert-codes/33b17884fd44a88d702bcbc48850d305 to your computer and use it in GitHub Desktop.
RenderOnVisible (source: https://jsfiddle.net/developit/vLbngh73/)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const { h, Component, render } = preact; /** @jsx h */ | |
| let q = []; | |
| function enqueue(fn, delay) { | |
| if (q.push(fn)==1) setTimeout(processQueue, delay); | |
| } | |
| function processQueue() { | |
| let p; | |
| while (p=q.pop()) p(); | |
| } | |
| class RenderOnVisible extends Component { | |
| static defaultProps = { | |
| fallback: <div />, | |
| debounce: 50, | |
| visible: false | |
| }; | |
| state = { | |
| visible: this.props.visible | |
| }; | |
| queueCheck = () => { | |
| if (!this.queued) { | |
| this.queued = true; | |
| enqueue(this.check, this.props.debounce); | |
| } | |
| }; | |
| check = () => { | |
| this.queued = false; | |
| if (this.state.visible) { | |
| this.unhook(); | |
| return true; | |
| } | |
| let bbox = this.base.getBoundingClientRect(), | |
| viewportHeight = window.innerHeight || document.documentElement.offsetHeight; | |
| if (bbox.top<=viewportHeight && bbox.bottom>=0) { | |
| this.unhook(); | |
| this.setState({ visible:true }); | |
| return true; | |
| } | |
| }; | |
| unhook() { | |
| removeEventListener('scroll', this.queueCheck); | |
| removeEventListener('resize', this.queueCheck); | |
| } | |
| componentDidMount() { | |
| if (!this.check()) { | |
| addEventListener('scroll', this.queueCheck); | |
| addEventListener('resize', this.queueCheck); | |
| } | |
| } | |
| componentWillUnmount() { | |
| this.unhook(); | |
| } | |
| render({ fallback, children }, { visible }) { | |
| let child = children[0]; | |
| if (typeof child==='function') return child(visible); | |
| return visible ? child : fallback; | |
| } | |
| } | |
| class DemoWidget extends Component { | |
| componentWillMount() { | |
| //console.log(this.props.id+' mounting'); | |
| } | |
| componentDidMount() { | |
| setTimeout( () => this.setState({ mounted:true }), 10); | |
| } | |
| componentWillUnmount() { | |
| console.log(this.props.id+' UNmounting'); | |
| } | |
| render({ id }, { mounted=false }) { | |
| return ( | |
| <div class="widget" mounted={mounted}> | |
| {id} | |
| </div> | |
| ); | |
| } | |
| } | |
| const Demo = () => { | |
| let kids = []; | |
| for (let i=1; i<=100; i++) { | |
| kids.push( | |
| i>90 ? ( | |
| // example: manually specify initial visibility: | |
| <RenderOnVisible visible> | |
| <DemoWidget id={i} /> | |
| </RenderOnVisible> | |
| ) : i<=50 ? ( | |
| // example: function-as-children to control it yourself | |
| <RenderOnVisible> | |
| { visible => ( | |
| visible ? <DemoWidget id={i} /> : <div class="fallback" /> | |
| ) } | |
| </RenderOnVisible> | |
| ) : ( | |
| // example: default compositional behavior with fallback option | |
| <RenderOnVisible fallback={<div class="fallback" />}> | |
| <DemoWidget id={i} /> | |
| </RenderOnVisible> | |
| ) | |
| ); | |
| } | |
| return <div class="demo">{kids}</div>; | |
| }; | |
| render(<Demo />, document.body); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| html, body { | |
| font: 16px/1.21 'Helvetica Neue',helvetica,arial,sans-serif; | |
| font-weight: 300; | |
| } | |
| .demo { | |
| margin: 25px; | |
| padding: 25px; | |
| background: #DDD; | |
| } | |
| .fallback { | |
| position: relative; | |
| padding: 20px; | |
| margin: 20px; | |
| height: 60px; | |
| } | |
| .widget { | |
| position: relative; | |
| padding: 20px; | |
| margin: 20px; | |
| background: burlywood; | |
| box-shadow: 0 1px 5px rgba(0,0,0,0.3); | |
| font-size: 50px; | |
| color: #555; | |
| text-align: center; | |
| &[mounted] { | |
| transition: background 1s ease; | |
| background: #FFF; | |
| &:after { | |
| content: 'MOUNTED'; | |
| position: absolute; | |
| display: block; | |
| left: 0; | |
| width: 100%; | |
| bottom: 10px; | |
| color: #999; | |
| font-size: 12px; | |
| animation: bounce .5s cubic-bezier(.5,0,.1,1.5) forwards 1; | |
| } | |
| } | |
| } | |
| @keyframes bounce { | |
| from { transform: scale(0.01); } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment