Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fire track event when element becomes visible #107

Open
dhruvg opened this issue Nov 3, 2018 · 2 comments
Open

Fire track event when element becomes visible #107

dhruvg opened this issue Nov 3, 2018 · 2 comments
Labels

Comments

@dhruvg
Copy link

dhruvg commented Nov 3, 2018

First off, thanks for making this. I have been using react-tracking for a few months now and it's so clean while getting me the granularity of tracking I desire. Kudos.

I am curious how users of this library check for component visibility before firing an event. A simple use case is that I have a hidden alert on the page. I want to fire a "show" event when this alert becomes visible (not when it is mounted). This use case is pretty common -- think modals, buttons which are invisible on small screens but become visible on large screens, etc...

So far, the best I have come up with is to use an external library to track component visibility and combine that with react-tracking to fire events then the component becomes visible. But it's clunky. I am envisioning something like this instead:

@track(props => ({ button: props.id, event: 'button.show' }), { dispatchOnVisible: true })
class MyButton extends PureComponent {
  ...
}

Thoughts?

@dhruvg dhruvg changed the title Fire track even when element becomes visible Fire track event when element becomes visible Nov 3, 2018
@tizmagik
Copy link
Collaborator

tizmagik commented Nov 4, 2018

Hey @dhruvg thanks for the kudos, that's appreciated and I'm glad you're making good use of react-tracking 😁

So for this use case, you actually have a few options.

Visibility is driven by props

If the visibility of the component is driven by the parent, and thus, by props, then you can actually optionally dispatch a tracking call by returning a falsy value initially and then the object to dispatch when the "show" prop is toggled. Something like:

@track(props => props.hidden ? false : ({ button: props.id }))
class MyButton extends PureComponent { ... }

Although in this case it's probably better to just have the parent not render the component until it should be shown, but it depends where the visibility logic exists.

Visibility is driven by state

If, instead, the component itself manages its own hidden/shown state, then I think you should be able to do something similar:

@track(props => ({ button: props.id }))
class MyButton extends Component {

  // return obj for dispatch while state.hidden is true because we're about to flip it
  @track((props, state) => state.hidden ? ({ event: 'button.show' )} : false) 
  toggleState() { 
    this.setState({ hidden: !this.state.hidden })
  }

  ...
}

Visibility determined by physical visibility in the viewport

This is when an external library, like @rsearchgate/react-intersection-observer (or the straight IntersectionObserver API) can be used.

import React, { Component } from 'react';
import 'intersection-observer'; // optional polyfill
import Observer from '@researchgate/react-intersection-observer';
import track from 'react-tracking';

@track(props => ({ button: props.id })
class MyButton extends Component {

    @track({ event: 'button.show' })
    handleIntersection(event) {
        console.log(event.isIntersecting);
    }

    render() {
        const options = {
            onChange: this.handleIntersection,
            root: '#scrolling-container',
            rootMargin: '0% 0% -25%',
        };

        return (
            <div id="scrolling-container" style={{ overflow: 'scroll', height: 100 }}>
                <Observer {...options}>
                    <div>I am the target element</div>
                </Observer>
            </div>
        );
    }
}

Of course, this would require an IntersectionObserver polyfill for some browsers.


As you can see the use cases for what "visible" means can be very different depending on use case. And even if we can agree that visibility means visible in the viewport, even that can be variable (e.g. how close to the viewport, any buffer? etc). So I hesitate to include this as a built-in feature to react-tracking, but the primitives are there.

Additionally, you could build your own HoC wrapper that encompasses this logic if visibility means the same thing for your app everywhere. Something like a @trackWhenVisible decorator. 😁

Hope that's helpful!

@dhruvg
Copy link
Author

dhruvg commented Nov 8, 2018

Thanks for the in-depth response. I am aiming for the visibility in viewport option. I will give the external lib + HoC a shot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants