Closed jgoux closed 7 years ago
I'm missing exactly this.
I'm structuring my components just like @jgoux does, you can see a working example here: https://github.com/mrtnbroder/universal-react-webpack-boilerplate (in js)
take a look at the src/Application folder, where each component exposes it's route, update, view etc. functions and where react-router consumes it at the top level.
This ported to purescript-pux would be awesome!
Routes could be composed with the Match
applicative functor? Pretend I used qualified modules instead of ugly names:
-- App.purs
data AppR
= WrapRepo RepoR
| WrapDashboard DashboardR
| NotFoundR
appMatch :: Match AppR
appMatch =
WrapRepo <$> repoMatch
<|> WrapDashboard <$> dashboardMatch
<|> pure NotFoundR
-- Repo.purs
data RepoR = Repo {owner :: String, name :: String, subroute :: RepoSubR}
data RepoSubR
= Issue IssueR
| ViewFile String
repoMatch :: Match RepoR
repoMatch = lit "repo" *> (mk <$> str <*> str <*> (Issue <$> issueMatch <|> fileMatch))
where
mk owner name subroute = Repo {owner, name, subroute}
fileMatch = lit "view-file" *> (ViewFile <$> str)
-- Issue.purs
data IssueR
= New
| View Int
| List
issueMatch :: Match IssueR
issueMatch = lit "issue" *>
((lit "new" *> pure New)
<|> (lit "view" *> (View <$> int))
<|> (lit "list" *> pure List))
-- Dashboard.purs
data DashboardR = Dashboard -- TODO
dashboardMatch :: Match DashboardR
dashboardMatch = lit "dashboard" *> pure Dashboard
With inspirations from the react router and ui-router i've come up with the following prototype: Define the routes in a nested structure:
route :: ∀ e. Route AppAction AppState e
route =
Route "bla" (C.wrapManyWith navigationBar) [
Route "blub" nestedStatefulRoute [
Route "here" (const typeHereComp) [],
Route "here" (const otherComponent) []
],
Route "bar/foo" (const helloComponent) [],
Route "something" (C.wrapManyWith $ caption "Here is something") [
Mount $ map implantInApp <<< childRouter
]
]
....
Every route has a component assigned (Route <path> <component> <children>
). The component is responsible to view and update the sub-route components.
A component may defines its own route-tree which then can be mounted in any other route (Mount $ map implantInApp <<< childRouter
) a.k.a. composition.
Finally a root-router is needed to handle the url-changed event and display/update the current active routes:
main :: Eff _ Unit
main = do
url <- PuxRouter.sampleUrl
let rootComp = rootRouter route
app <- Pux.start {
initialState : init,
update: C.update rootComp,
view : C.view rootComp,
inputs: [UrlChanged <$> url]
}
PuxRouter.navigateTo "bla/blub"
Pux.renderToDOM "#app" app.html
To make this work we need the concept of a component (update + view function) in pux, this is the same problem as described in #31 (Nesting arbitrary components). So i've reused https://gist.github.com/sloosch/ea98c0c58f9440903c98b952265b556e#file-component-purs
Here is the working prototype in action: and the full source: https://gist.github.com/sloosch/72c62d30800f1f27a1bc55095c40cd60
Is this what you were asking for? Anyone interested in putting this into a purescript-pux-nested-router? Does anyone know how this is handled in Elm?
Maybe the solution described by spencerjanssen is a better fit. Hadn't time to explore it further to the point where states and actions come into play.
Here is my proof of concept library which tackles this problem from different perspective - alternative (bidirectional - all urls are generated) routing engine:
https://github.com/paluh/purescript-puxing-bob
Please look into examples/multiple-components-routing for working example. Unfortunately view
's type became a bit complicated in my approach, because we need to somehow add parent's context to generated urls.
Thanks all for the answers ! :+1:
I like all the approaches proposed, even if I don't fully understand them (yet).
I think @sloosch is my favorite because it's the closest to react-router. :smile:
I'd be more than interested to see a purescript-pux-nested-router
.
Questions for @sloosch :
import Component as C
?Questions for @spencerjanssen :
NotFound
view has to know that the current url is reachable, so having this kind of composition in it makes total sense. How would you implement intermediate NotFound
in a sub-component ?Question for all :
child :: Maybe Child.State
to handle the case when the child isn't mounted ?I also think setting up a little app showing routing capabilities of each solution would be great, so we can compare from a common ground.
I'm archiving most of the discussion threads. If you'd like to continue the discussion I'd prefer if you posted a question on StackOverflow or Gitter. Thanks.
Hello :hand:,
I'd like to organize my application in a fractal manner. To do so, I need to be able to declare routes locally with their corresponding component. I was able to do it in JS using react + react-router's route object.
Here is an example splitting the current page into components :
So we have this hierarchy of components for the current page
https://github.com/alexmingoia/purescript-pux/issues/new
:Application → Repository → Issues → NewIssue
The idea here is to organize these components according to their relation
Parent → Child
:We can identify "routable" components which display different children based on the current URI. If we imagine that each "routable" component consume a part of the URI as we go deep in the hierarchy we can say that :
Application
displays its childRepository
when the URI is:username/:projectname
Repository
displays its childIssues
when the URI isissues
Issues
displays its childNewIssue
when the URI isnew
and its childIssueList
when the URI is/
or `` (this case can be considered as its index route)In that way, a "routable" component just needs to care about its own part of the URI, and know nothing outside of its direct children.
For the routes definition, we could add a
Route
data type to each "routable" component definition in addition to the usualState, Action, init, update, view
.This is where I stopped, now I'm looking for a way to declare local
match
functions, consume and pass the current URI to children so I can repeat the pattern down the hierarchy. :sos: