Redirection to another during page load causes the view to not render.
mjstahl opened this issue · comments
Expected behavior
I am brand new to Choo so I may be thinking about this all wrong. But the use case is, the User comes to a route that requires authentication. They are not authenticated so they are routed to a login view at a different route.
I have written up a small Choo to make it easier to demostrate the problem. The expected result from the code below is:
Should ONLY EVER get here.
And the route should be:
package.json
{
"name": "test-choo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"bankai": "^9.14.0",
"choo": "^6.13.0"
}
}
index.js
const choo = require('choo')
const html = require('choo/html')
const app = choo()
app.use((state, emitter) => { state.session = null })
app.route('/', (state, emit) => {
if (!state.session) emit(state.events.REPLACESTATE, '/login')
return html`
<body>
<p>Should NEVER get here.</p>
</body>
`
})
app.route('/login', (state, emit) => {
return html`
<body>
<p>Should ONLY EVER get here.</p>
</body>
`
})
app.mount('body')
Actual behavior
The actual result is:
Should NEVER get here.
And the route should be:
Steps to reproduce behavior
Write here.
- Copy the above files into a folder
npm i
./node_modules/.bin/bankai start index.js
- In a browser open,
https://localhost:8080/
Notes
What I noticed when tracing the function calls was that NAVIGATE event emitted and its callback executed.
In the start
function (which was called after documentReady
in mount
), the RENDER event was never emitted because self._loaded
was false (https://github.com/choojs/choo/blob/master/index.js#L101). After this code is executed, the documentReady
callback in start
is called, setting self._loaded
to true.
So it appears that there is an order of operations issue maybe caused by the setTimeout
in the documentReady
call.
I would like to fix this problem (assuming its a problem), but I need a little bit of hand holding since I am only 1 day into Choo. Any guidance would be greatly appreciated.
Thanks for kareniel
on IRC for the following snippet. I do think there could be a good way to work this into documentation. Maybe a tangent in the Forms
documentation?
views/protect.js
const login = require('./login');
module.exports = function protect (view) {
return function (state, emit) {
if (!state.isLoggedIn) {
emit(state.events.REPLACESTATE, '/login')
return login(state, emit)
}
return view(state, emit)
}
}
index.js
app.route('/home', protect(require('./views/home')))