-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathfullExample.tsx
More file actions
165 lines (131 loc) · 4.05 KB
/
fullExample.tsx
File metadata and controls
165 lines (131 loc) · 4.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import { createHashHistory } from 'history'
import { autorun, makeAutoObservable, reaction } from 'mobx'
import { observer } from 'mobx-react-lite'
import * as React from 'react'
import { XRoute, XRouter } from 'xroute'
//
// Define some routes
//
const HomeRoute = XRoute('home')
.Resource('/') // Optional language param, eg. /en or /
.Type<{
pathname: {}
search: { language?: 'en' | 'da' | 'de' }
}>()
const UserProfileRoute = HomeRoute.Extend('userProfile')
.Resource('/user/:userId') // Required language, eg. /da/user/11
.Type<{
pathname: { userId: string }
search: { profileSection: 'profile' | 'preferences' }
hash?: 'foo' | 'baz'
}>()
const router = new XRouter([UserProfileRoute, HomeRoute], createHashHistory())
export type MyXRouter = typeof router
// Log some changes
autorun(() => console.log('Active route:', router.route))
// Navigate to: /?language=en
router.routes.home.push({ pathname: { language: 'en' } })
// Get the pathname, eg. to put inside an <a href="" />
const homeDaUri = router.routes.home.toUri({ pathname: { language: 'da' } }) // "/da"
// Navigates to: /user/11?language=en
router.routes.userProfile.push({
pathname: { userId: '11' },
search: { language: 'en' },
})
// Just change the language in the active route.
// This works as long as the parameter is shared between all routes.
// Navigates to: /user/11?language=da
router.route?.push({ pathname: { language: 'da' } })
// Re-use the current language
// Navigates to: /?language=da
router.routes.home.push({
search: { language: router.route?.search.language },
})
// Provide a route object to route from anywhere:
// Navigate to: /de/user/55
router.push(UserProfileRoute, {
pathname: { userId: '55' },
search: { language: 'de', profileSection: 'profile' },
// hash: undefined,
// hash: 'notvalid',
hash: 'baz',
})
// Read route properties:
/** This must be read from the `routes.userProfile` for the type to be consistent */
router.routes.userProfile.pathname?.userId // => '55'
/** Because `language` is available on all routes, we can read it from the active route at `router.route` */
router.route?.search?.language
class UserProfilePage {
constructor(private router: MyXRouter) {
this.router = router
makeAutoObservable(this)
}
get route() {
return this.router.routes.userProfile
}
get userId() {
return this.route.pathname?.userId
}
get profileSection() {
return this.route.search?.profileSection
}
setUserId(userId: string) {
// Uses current route params
this.route.push({ pathname: { userId } })
//
// or
//
// Explicitly use previous params...
this.route.pushExact((uri) => ({
...uri,
pathname: { ...uri.pathname, userId },
}))
}
setProfileSection(profileSection: this['profileSection']) {
this.route.push({ search: { profileSection } }) // sets ?profileSection=""
}
}
// Play around with user profile:
void (async () => {
const userProfilePage = new UserProfilePage(router)
userProfilePage.userId // 55
userProfilePage.setUserId('200')
await new Promise((r) => setTimeout(r, 50)) // Give it time to update the URL and come back...
userProfilePage.userId // 200
})()
const Component = observer(() => {
const [router] = React.useState(
() => new XRouter([UserProfileRoute, HomeRoute], createHashHistory()),
)
return (
<>
<nav>Active Language: {router.route?.search.language}</nav>
{router.route?.key === 'home' && <div>Home Page!</div>}
{
// Or do this:
}
{router.routes.userProfile.isActive && (
<div>
User Profile! UserID: {router.routes.userProfile.pathname?.userId}
</div>
)}
</>
)
})
const listenToUserProfileRoute = () => {
let previousIsActive: boolean
reaction(
() => router.routes.userProfile.isActive,
(isActive) => {
if (isActive === previousIsActive) return // Ignore same state
previousIsActive = isActive
if (isActive) {
// on enter route
// ...
} else {
// on exit route
// ...
}
},
)
}