choojs / choo

:steam_locomotive::train: - sturdy 4kb frontend framework
https://choo.io/
MIT License
6.78k stars 595 forks source link

Match initial route before stores are called #681

Closed lachenmayer closed 5 years ago

lachenmayer commented 6 years ago

Hello choo croo, I just made a store that needs to get a URL param from state.params - I was only able to get it after the DOMContentLoaded event, which I thought was a bit weird.

Basically, when I navigate to /thingy/foo, I'd like to do this:

app.route('/thingy/:id', (state, emit) => html`<div>this is thingy ${state.params.id}</div>`)
app.use((state, emitter) => {
  console.log(state.params.id) // <= expected: foo
  // actual: state.params is undefined :(
  emitter.on('DOMContentLoaded', () => {
    console.log(state.params.id) // this works though
  })
})

I see no reason why I shouldn't be able to access the route info directly in the store - as far as I can tell, it doesn't interfere with any of the other things that happen on initial render.

This change just moves the this._matchRoute call in Choo.start & Choo.toString above the initial stores call.

I've added tests for state.params & state.href being set in the store, and also checked the expected behavior in my store :)

goto-bus-stop commented 6 years ago

the ordering here is kinda tough but I think we want to be able to init stores before handling routes, so eg a store can add routes, allowing you to split things up into modules etc:

app.use(require('./routes'))
app.use(require('choo-login-page-module-from-npm'))

currently that doesn't work in bankai pending https://github.com/choojs/bankai/pull/452 but imo, waiting for DOMContentLoaded would be the correct way to go.

does that make sense?

lachenmayer commented 5 years ago

Hmm, that's an interesting usecase I hadn't considered! I wish I could at least get "best-effort" route info, but that could potentially be even more confusing... Will use DOMContentLoaded for now, cheers!