I'm not sure if this is the best place to ask for this kind of thing, but I'm moving my small site over to Choo (or trying) from React. I'm my React site, I have a visibility watcher component and a dimension watcher component that get some info from the DOM node, and pass it as a prop to a child component.
Here's the example of my React components:
// Dimension watcher
//
// Example Usage:
// Wrap MyComponent...
// `export default dimensionWatcher()(MyComponent);`
// Then MyComponent will have { width, height } props.
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { debounce } from '../../utils';
const getDimensions = (element) => {
const { width, height } = element.getBoundingClientRect();
return { width, height };
};
const dimensionWatcher = () => WrappedComponent => class extends Component {
constructor(props) {
super(props);
this.state = {
width: null,
height: null
};
this.element = null;
this.onResize = debounce(this.onResize, 200).bind(this);
}
componentDidMount() {
this.element = ReactDOM.findDOMNode(this);
this.setState(getDimensions(this.element));
window.addEventListener('resize', this.onResize);
}
componentWillUnmount() {
window.removeEventListener('resize', this.onResize);
}
onResize() {
this.setState(getDimensions(this.element));
}
render() {
return (
<WrappedComponent {...this.props} width={this.state.width} height={this.state.height} />
);
}
};
export default dimensionWatcher;
// Visibility watcher
//
// Example Usage:
// Wrap MyComponent...
// `export default visibilityWatcher({ opts })(MyComponent);`
// Then MyComponent will have { isVisible } props.
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { debounce } from '../../utils';
const visibilityWatcher = (
offset = 0,
once = true,
interval = 25
) => WrappedComponent => class extends Component {
constructor(props) {
super(props);
this.state = {
isVisible: false
};
this.checkInterval = null;
this.element = null;
this.onResize = debounce(this.onResize, 200).bind(this);
}
componentDidMount() {
this.element = ReactDOM.findDOMNode(this);
this.checkVisibility(this.element);
this.checkInterval = setInterval(() => {
this.checkVisibility(this.element);
}, interval);
window.addEventListener('resize', this.onResize);
}
componentWillUnmount() {
clearInterval(this.checkInterval);
window.removeEventListener('resize', this.onResize);
}
onResize() {
this.checkVisibility(this.element);
}
checkVisibility(element) {
const rect = element.getBoundingClientRect();
const windowHeight = window.innerHeight || document.documentElement.clientHeight;
let isVisible = false;
if (rect.bottom >= 0 && rect.top <= (windowHeight + offset)) {
isVisible = true;
}
if (isVisible) {
this.setState({ isVisible });
}
if (isVisible && once) {
window.clearInterval(this.checkInterval);
}
}
render() {
return (
<WrappedComponent {...this.props} isVisible={this.state.isVisible} />
);
}
};
export default visibilityWatcher;
I'm wondering how I can create this in Choo. I have the currying part fine, but I can't seem to find a way that I can use getBoundingClientRect and add/remove event listeners to the component.
_I don't want to put the wrapped component in another element as that defeats the whole point of getting the elements dimensions. I just need to pass the dimensions to the child component._
This is what I have in Choo so far in terms of getting the right props etc:
import html from 'choo/html';
import { debounce } from '../../utils';
const getDimensions = (element) => {
const { width, height } = element.getBoundingClientRect();
return { width, height };
};
const dimensionWatcher = (wrappedComponent) => (props) => {
let width = null;
let height = null;
return html`${wrappedComponent(Object.assign({}, props, { width, height }))}`;
};
export default dimensionWatcher;
This is how I would use it:
// foo.js
const Foo = ({ name, width, height }) => {
return html`
<h1>Foo ${name}</h1>
`;
};
export default dimensionWatcher(Foo);
// in another component.js
...
return html`
<div>
${Foo({ name: 'Bar' })}
</div>`;
...
Any help would be greatly appreciated.
Not sure if this is the best answer, but I think this a direction that I would go in to start solving the issue:
var observeResize = require('observe-resize')
var intersectExists = require('on-intersect/exists')
var onViewport = require('on-intersect')
var html = require('choo/html')
var Foo = html`<h1 onload=${watcher}>wow</h1>`
function watcher (el) {
var stop = observeResize(el, function () {
console.log('resized')
stop()
})
if (intersectExists()) {
var stopObserving = onIntersect(el, onEnter, onExit)
}
function onEnter (entry) {
console.log(entry.time)
console.log(entry.rootBounds)
console.log(entry.intersectionRect)
console.log(entry.intersectionRatio)
console.log(entry.target)
document.body.setAttribute('style', 'background-color: green')
}
function onExit (entry) {
document.body.setAttribute('style', 'background-color: white')
stopObserving()
}
}
links to relevant modules:
https://github.com/yoshuawuyts/on-intersect
https://github.com/yoshuawuyts/observe-resize
It looks interesting, but I really like the pattern of composing the functions and passing the width & height as props to the component which keeps the onload function available on the component if I need it.
@samisking Could you solve your problem? Would you mind to share your findings?
Most helpful comment
@samisking Could you solve your problem? Would you mind to share your findings?