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

Debounce async request #37

Open
allthesignals opened this issue May 31, 2019 · 4 comments
Open

Debounce async request #37

allthesignals opened this issue May 31, 2019 · 4 comments

Comments

@allthesignals
Copy link

This addon is real gem - thank you for making it.

I started my own "data-store" component, which had a yield timeout(100) inside the restartable task. This is because the fetch is requested on mouse hover, which is too many requests at once. Hence, debounce.

Do you have any example of using your API to compose a similar behavior? I cannot quite see how the pieces would fit together.

I tried this, but I don't think that's what it's for:

        {{#needs-async
          needs=(async-all
            (array (timeout 100)
            (find-record 'modal-split' features.firstObject.properties.geoid))
          )
          as |states|
        }}
       {{/needs-async}}

Happy to add more to the examples section of the docs!

@dknutsen
Copy link
Owner

Hmmmm very interesting 🤔 how would you connect this to the on-hover event? Like is this block already getting conditionally rendered on hover somehow? Basically this should only make a request when it is rendered, so if you have issues with too many requests I'd think you'd also have issues with too many renders which isn't great either.

@dknutsen
Copy link
Owner

I guess I'd follow up on that by saying that (and I'm making some assumptions here so forgive me if this is off base) if you're rendering some sort of modal or popup (I'm inferring that mostly based on the record type) while hovering over something else, and you want that modal/popup to load a record using the snippet you posted above, I'd think you'd want to handle the "debounce" situation more "upstream".

My inclination would be to do something like:

  1. on mouseenter event for "thing that gets hovered on" you set a flag to show modal/popup to true, let's call it showModal. So on mouseenter showModal -> true
  2. on mouseleave event for "thing that gets hovered on" you set showModal to false
  3. render the modal/popup something like this:
{{#if showModal}}
  {{#modal-wrapper}}
    {{#needs-async
      needs=(find-record 'modal-split' features.firstObject.properties.geoid)
      as |states|
    }}

      {{!-- modal content here --}}

    {{/needs-async}}
  {{/modal-wrapper}}
{{/if}}

Again I'm making a lot of assumptions but like I said if you're seeing a ton of data requests you're probably also seeing a ton of rerenders which is also something you'd want to avoid. If you actually do want rerenders for whatever reason maybe consider turning background refresh off for that model type so a findRecord only makes the one request and then pulls from the store on consecutive fetches? There are other ways you could handle it too, like writing a custom helper or something...

@allthesignals
Copy link
Author

allthesignals commented May 31, 2019

@dknutsen thank you! I went ahead and composed stuff, adding what I needed on top of what you created :) here's what I got:

{{#with (debounce intersectingFeatures.firstObject.properties.geoid 400) as |geoIdTask|}}
  {{#needs-async needs=(find-record 'modal-split' geoIdTask.value) as |modalData|}}
    {{#modalData.loading}}
      <i class="spinner icon"></i>
    {{/modalData.loading}}
    {{#modalData.loaded as |data|}}
      {{data.count}}!
    {{/modalData.loaded}}
  {{/needs-async}}
{{/with}}

how would you connect this to the on-hover event? Like is this block already getting conditionally rendered on hover somehow? Basically this should only make a request when it is rendered, so if you have issues with too many requests I'd think you'd also have issues with too many renders which isn't great either.

Yup, it's yielded out from a contextual component, and gets passed into a UI card:

{{#mapbox/current-mouse-position map=map as |mapMouseEvent|}}
  {{#mapbox/intersecting-features map=map
    point=mapMouseEvent.point
    options=(hash layers=(array layerId)) as |intersectingFeatures|
  }}
    {{#if (and mapMouseEvent.point intersectingFeatures)}}
      {{#hover-card point=mapMouseEvent.point}}
{{!-- UI and Needs Async stuff here !}}

I think you're right about too many renders... I don't know how to address that, but I have it setup so that the hover UI box follows the mouse around when the mapMouseEvent gets updated. Separately, "modal" here just refers to "mode of transportation", not the UI concept.

I should probably group some of this together more but here's the full extent of where I landed:

{{#mapbox/current-mouse-position map=map as |mapMouseEvent|}}
  {{#mapbox/intersecting-features map=map
    point=mapMouseEvent.point
    options=(hash layers=(array layerId)) as |intersectingFeatures|
  }}
    {{#if (and mapMouseEvent.point intersectingFeatures)}}
      {{#hover-card point=mapMouseEvent.point}}
        <div class="ui card">
          <div class="content">
            <div class="header">{{intersectingFeatures.firstObject.properties.boroname}}</div>
            <div class="meta">
              <span>Census Tract ID: {{intersectingFeatures.firstObject.properties.geoid}}</span>
            </div>
            <div class="description">
              {{#with (debounce intersectingFeatures.firstObject.properties.geoid 400) as |geoIdTask|}}
                {{#needs-async needs=(find-record 'modal-split' geoIdTask.value) as |modalData|}}
                  {{#modalData.loading}}
                    <i class="spinner icon"></i>
                  {{/modalData.loading}}
                  {{#modalData.loaded as |data|}}
                    <div class="header">{{data.count}}</div>
                    <div class="meta">
                      <span>2 days ago</span>
                      <a>{{data.mode}}</a>
                    </div>
                    <p></p>
                  {{/modalData.loaded}}
                {{/needs-async}}
              {{/with}}
            </div>
          </div>
        </div>
      {{/hover-card}}
    {{/if}}
  {{/mapbox/intersecting-features}}
{{/mapbox/current-mouse-position}}

Here's some animation - it's not perfect, it does flicker a little bit, and I think I have some things a little out of order (it should start loading as soon as there's a settled ID to query for):

Anyways, this is super interesting! Thanks for the thoughtful, thorough response.

@dknutsen
Copy link
Owner

Oh that's awesome. I always love maps and geo data. Thanks for sharing! And glad you got something working. Definitely a trickier scenario if the modal has to move with the mouse but it looks like you're on the right track. Good luck! And definitely let me know if you have any ideas for the addon or examples while you're hacking around.

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

No branches or pull requests

2 participants