Hyperapp: onRoute hooks?

Created on 1 Mar 2017  路  9Comments  路  Source: jorgebucaran/hyperapp

I'm facing a problem where I need to fetch data when I enter different routes

Here's an example with just a single view that needs to fetch data. In reality I will have multiple views, and model.items will change on different views.

I'm not sure how to achieve this functionality without onRoute hooks.

example

const { h, app } = hyperapp
/** @jsx h */

app({
  model: {
    items: []
  },
  reducers: {
    updateItems: (model, data) => ({
      items: data
    })
  },
  effects: {
    fetch: (model, actions) => {
      setTimeout(function () {
        actions.updateItems([1, 2, 3])
      },0)
    }
  },
  view: (model, actions) => {
    /* I need to asynchronously fetch items only one time when I enter routes.
    If I call an effect here in the view, it will rerender infinitely
    since reducers update the model and cause views to render
    */
    actions.fetch()

    console.log('this is logged on every render')

    return (
      <div>{model.items}</div>
    )
  } 
})
Feature

Most helpful comment

Everything is cleared up, thanks!

All 9 comments

Sounds reasonable and something we will be able to achieve _without_ any hacks after https://github.com/hyperapp/hyperapp/issues/120.

@traducer With regards to this issue. I have a question. How are you switching views?

User clicks a link/button? What about fetching the view's data before you switch views?

You could create a function switchView(url, actions) that fetches some data and then calls actions.router.go(url) or some other combination.

Does I make sense?

@jbucaran hmm, the problem I'm having looks something like this:

-> user navigates to path /items
-> the view function for this route calls actions.fetchItems()
-> items get fetched from the server and updates model.items
-> view rerenders on model change

the problem is everytime the view is rendered, actions.fetchItems is being called, which is creating an infinite loop since new items are updating the model. I want to be able to call actions.fetchItems only once when someone navigates to that route.

Switching views your way works perfectly fine. A click event would only call actions.fetchItems once and actions.router.go(url) would change routes. But what if they refresh the page or manually type in the pathname in their browser address bar? How would that data be fetched?

I hope this makes sense.

@traducer

``javascript app({ actions: { fetch (model, actions) => console.log(fetching ${model.router.params.id}`)
,
customGo: (model, actions, path) => {
actions.router.go(path)
actions.fetch()
}
},
subscriptions: [
(model, actions) => actions.fetch()
]
})

@dodekeract This actually looks like a nice solution to my problem.

I didn't think of using subscriptions to fetch the initial data. I guess I can just check the location.pathname in the subscriptions as well to fetch data depending on the pathname?

```javascript
subscriptions: [
(model, actions) => {
switch (location.pathname) {
case '/items':
actions.fetchItems()
return
}
}
````

This actually clears things up for me. Thanks @dodekeract

@traducer In theory the router should do that for you. It stores everything you need in model.router.match and model.router.params.

That also has the advantage that you don't have to manually match /item/:id. (model.router.params.id)

@dodekeract Ah I see now. I was still using version 0.5 so I didn't see those changes.

@dodekeract Thanks for figuring out!

@traducer Do you want to close?

Everything is cleared up, thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jacobtipp picture jacobtipp  路  3Comments

jbrodriguez picture jbrodriguez  路  4Comments

jorgebucaran picture jorgebucaran  路  3Comments

jscriptcoder picture jscriptcoder  路  4Comments

zaceno picture zaceno  路  3Comments