You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: packages/overmind-website/guides/intermediate/02_routing.md
+15-15Lines changed: 15 additions & 15 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,17 +2,17 @@
2
2
3
3
With Overmind you can use whatever routing solution your selected view layer provides. This will most likely intertwine routing state with your component state, which is something Overmind would discourage, but you know... whatever you feel productive in, you should use :-) In this guide we will look into how you can separate your router from your components and make it part of your application state instead. This is more in the spirit of Overmind and throughout this guide you will find benefits of doing it this way.
4
4
5
-
We are going to use [pagejs](https://www.npmjs.com/package/page) as the router and we will look at a complex routing example where we open a page with a link to a list of users. When you click a user in the list we will show that user in a modal with the url updating to the id of the user. In addition we will present a query parameter that reflects the current tab inside the modal.
5
+
We are going to use [page.js](https://www.npmjs.com/package/page) as the router and we will look at a complex routing example where we open a page with a link to a list of users. When you click on a user in the list we will show that user in a modal with the URL updating to the id of the user. In addition we will present a query parameter that reflects the current tab inside the modal.
6
6
7
-
We will start with a simple naive approach and then we are going to tweak our approach a little bit for the optimal solution.
7
+
We will start with a simple naïve approach and then tweak our approach a little bit for the optimal solution.
8
8
9
9
## Set up the app
10
10
11
11
Before we go into the router we want to set up the application. We have some state helping us express the UI explained above. In addition we have three actions.
12
12
13
13
1.**showHomePage** tells our application to set the current page to *home*
14
14
2.**showUsersPage** tells our application to set the current page to *users* and fetches the users as well
15
-
3.**showUserModal** tells our application to show the modal by setting an id of a user passed to the action. This action will also handle the switching of tabs later
15
+
3.**showUserModal** tells our application to show the modal by setting an id of a user passed to the action. This action will also handle the switching of tabs later.
**Pagejs** is pretty straight forward. We basically want to map a url to trigger an action. To get started let us first add Pagejs as an effect and let us take the opportunity to create a custom API. When a url triggers we want to pass the params of the route to the action linked to the route:
24
+
**Page.js** is pretty straightforward. We basically want to map a URL to trigger an action. To get started, let us first add Page.js as an effect and take the opportunity to create a custom API. When a URL triggers we want to pass the params of the route to the action linked to the route:
25
25
26
26
```marksy
27
27
h(Example, { name: "guide/routing/effect" })
28
28
```
29
29
30
-
Now we can use Overminds**onInitialize** to configure the router. That way the initial url triggers before the UI renders and we get to set our initial state.
30
+
Now we can use Overmind's**onInitialize** to configure the router. That way the initial URL triggers before the UI renders and we get to set our initial state.
31
31
32
32
```marksy
33
33
h(Example, { name: "guide/routing/pagejs" })
@@ -37,19 +37,19 @@ Take notice here that we are actually passing in the params from the router, mea
37
37
38
38
## The list of users
39
39
40
-
When we now go to the list of users the list loads up and is displayed. When we click a user the url changes, our **showUser** action runs and indeed, we see a user modal.
40
+
When we now go to the list of users the list loads up and is displayed. When we click on a user the URL changes, our **showUser** action runs and indeed, we see a user modal.
41
41
42
42
43
43
```marksy
44
44
h(Example, { name: "guide/routing/users" })
45
45
```
46
46
47
47
48
-
But what if we try to refresh now... we get an error. The router tries to run our user modal, but we are on the frontpage. The modal does not exist there. We want to make sure that when we open a link to a user modal we also go to the actual user list page.
48
+
But what if we try to refresh now... we get an error. The router tries to run our user modal, but we are on the front page. The modal does not exist there. We want to make sure that when we open a link to a user modal we also go to the actual user list page.
49
49
50
50
## Composing actions
51
51
52
-
A straight forward way to solve this is to simply also change the page in the **showUserModal** action, though we would like the list of users to load in the background as well. The logic of **showUsers** might also be a lot more complex and we do not want to duplicate our code. When these scenarios occur, where you want to start calling actions from actions, it indicates you have reached a level of complexity where a functional approach might be better. Let us look at how you would implement this both using a functional approach and a plain imperative one.
52
+
A straightforward way to solve this is to simply also change the page in the **showUserModal** action, though we would like the list of users to load in the background as well. The logic of **showUsers** might also be a lot more complex and we do not want to duplicate our code. When these scenarios occur where you want to start calling actions from actions, it indicates you have reached a level of complexity where a functional approach might be better. Let us look at how you would implement this both using a functional approach and a plain imperative one.
53
53
54
54
### Imperative approach
55
55
```marksy
@@ -65,9 +65,9 @@ When running actions from within other actions like this it will be reflected in
65
65
h(Example, { name: "guide/routing/compose" })
66
66
```
67
67
68
-
By splitting up all our logic into operators we were able to make our actions completely declarative and at the same time reuse logic across them. The *operators* file gives us maintaineable code and the *actions* file gives us readable code.
68
+
By splitting up all our logic into operators we were able to make our actions completely declarative and at the same time reuse logic across them. The *operators* file gives us maintainable code and the *actions* file gives us readable code.
69
69
70
-
We could actually make this better though. There is no reason to wait for the user of the modal to load before we load the users list in the background. We can fix this with the **parallel** operator. Now the list of users and the single user loads at the same time.
70
+
We could actually make this better though. There is no reason to wait for the user of the modal to load before we load the users list in the background. We can fix this with the **parallel** operator. Now the list of users and the single user load at the same time.
71
71
72
72
```marksy
73
73
h(Example, { name: "guide/routing/parallel" })
@@ -77,21 +77,21 @@ Now you are starting to see how the operators can be quite useful to compose flo
77
77
78
78
## The tab query param
79
79
80
-
**Pagejs** also allows us to manage query strings, the stuff after the **?** in the url. Pagejs does not parse it though, so we introduce a library which does just that, [query-string](https://www.npmjs.com/package/query-string). With this we can update our router to also pass in any query params.
80
+
**Page.js** also allows us to manage query strings, the stuff after the **?** in the url. Page.js does not parse it though, so we introduce a library which does just that, [query-string](https://www.npmjs.com/package/query-string). With this we can update our router to also pass in any query params.
81
81
82
82
83
83
```marksy
84
84
h(Example, { name: "guide/routing/query" })
85
85
```
86
86
87
87
### Imperative approach
88
-
We now also handle the received tab param and make sure that when we change tabs we do not load the user again. We only want to load the user when there is no existing user or if the user has changed.
88
+
We now also handle the received tab parameter and make sure that when we change tabs we do not load the user again. We only want to load the user when there is no existing user or if the user has changed.
Now we can add an operator which uses this **tab** query to set the current tab and then compose it into the action. We also add an operator to verify if we really should load a new user.
With little effort we were able to build a custom "**application state first**" router for our application. Like many common tools needed in an application, like talking to the server, local storage etc., there are often small differences in the requirements. And even more often you do not need the full implementation of the tool you are using. By using simple tools you can meet the actual requirements of the application more "head on" and this was an example of that.
103
+
With little effort we were able to build a custom "**application state first**" router for our application. Like many common tools needed in an application, like talking to the server, localStorage etc., there are often small differences in the requirements. And even more often you do not need the full implementation of the tool you are using. By using simple tools you can meet the actual requirements of the application more "head on" and this was an example of that.
104
104
105
-
We also showed off how you can solve this issue with an imperative approach or go functional. In this example functional is probably a bit overkill as there is very little composition required. But if your application needed to use these operators many times in different configurations you would benefit more from it.
105
+
We also showed how you can solve this issue with an imperative approach or go functional. In this example functional is probably a bit overkill as there is very little composition required. But if your application needed to use these operators many times in different configurations you would benefit more from it.
0 commit comments