@tinkoff/router 0.2.6 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -276
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Routing library. It can work both on the server and on the client. Designed primarily for building isomorphic applications.
|
|
4
4
|
|
|
5
|
+
Link to complete Router documentation - https://tramvai.dev/docs/features/routing/overview/
|
|
6
|
+
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
7
9
|
You need to install `@tinkoff/router`:
|
|
@@ -13,285 +15,9 @@ yarn add @tinkoff/router
|
|
|
13
15
|
And connect it to the project:
|
|
14
16
|
|
|
15
17
|
```tsx
|
|
16
|
-
import { Router } from '@tinkoff/router';
|
|
17
|
-
|
|
18
|
-
const router = new Router();
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Explanation
|
|
22
|
-
|
|
23
|
-
Features:
|
|
24
|
-
|
|
25
|
-
- The library supports options for working both on the server and on the client.
|
|
26
|
-
- It is possible to use different client transition options: with or without SPA transitions.
|
|
27
|
-
- There are Guards to check the availability of a route under specific conditions.
|
|
28
|
-
- You can subscribe to different stages of the transition through hooks
|
|
29
|
-
- Components and hooks for easy routing from react
|
|
30
|
-
|
|
31
|
-
### Server and client version
|
|
32
|
-
|
|
33
|
-
It is enough just to import routing from the library itself and, based on the settings in package.json, the required version for the server or client will be returned
|
|
34
|
-
|
|
35
|
-
```ts
|
|
36
|
-
import { Router } from '@tinkoff/router';
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### Client routing with/without SPA transitions
|
|
40
|
-
|
|
41
|
-
By default, routing with SPA transitions is enabled on the client. If you need to disable SPA transitions, you need to import a special version of the routing
|
|
42
|
-
|
|
43
|
-
```ts
|
|
44
18
|
import { Router, SpaHistory } from '@tinkoff/router';
|
|
45
19
|
import { NoSpaRouter } from '@tinkoff/router';
|
|
46
20
|
|
|
47
21
|
const spaRouter = new Router({ history: new SpaHistory() });
|
|
48
22
|
const noSpaRouter = new NoSpaRouter();
|
|
49
23
|
```
|
|
50
|
-
|
|
51
|
-
### Router Guards
|
|
52
|
-
|
|
53
|
-
Guards allow you to control the availability of a particular route for a specific transition. From the guard, you can block the transition or initiate a redirect.
|
|
54
|
-
|
|
55
|
-
```ts
|
|
56
|
-
import { NavigationGuard } from '@tinkoff/router';
|
|
57
|
-
|
|
58
|
-
export const myGuard: NavigationGuard = async ({ to }) => {
|
|
59
|
-
if (to.config.blocked) {
|
|
60
|
-
return false; // block this transition
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (typeof to.config.redirect === 'string') {
|
|
64
|
-
return to.config.redirect; // call a redirect to the specified page
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (typeof to.config.needAuth && !isAuth()) {
|
|
68
|
-
return { url: '/login/', code: '302' }; // redirect to page with NavigateOptions
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// if nothing is returned, the transition will be performed as usual
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
router.registerGuard(myGuard);
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
#### Rules
|
|
78
|
-
|
|
79
|
-
- guards are asynchronous and it execution will be awaited inside routing
|
|
80
|
-
- all guards are running in parallel and they are all awaited
|
|
81
|
-
- if several guars return something then the result from a guard that was registered early will be used
|
|
82
|
-
|
|
83
|
-
#### Possible result
|
|
84
|
-
|
|
85
|
-
The behaviour of routing depends on the result of executing guards functions and there result might be next:
|
|
86
|
-
|
|
87
|
-
- if all of the guards returns `undefined` than navigation will continue executing
|
|
88
|
-
- if any of the guards returns `false` than navigation is getting blocked and next action differs on server and client
|
|
89
|
-
- if any of the guards returns `string` it is considered as url to which redirect should be happen
|
|
90
|
-
- if any of the guards returns [`NavigateOptions`](#navigateoptions) interface, `url` property from it is considered as url to which redirect should be happen
|
|
91
|
-
|
|
92
|
-
### Transitions hooks
|
|
93
|
-
|
|
94
|
-
Transition hooks allow you to perform your asynchronous actions at different stages of the transition.
|
|
95
|
-
|
|
96
|
-
```ts
|
|
97
|
-
import { NavigationHook } from '@tinkoff/router';
|
|
98
|
-
|
|
99
|
-
export const myHook: NavigationHook = async ({ from, to, url, fromUrl }) => {
|
|
100
|
-
console.log(`navigating from ${from} to route ${to}`);
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
router.registerHook('beforeNavigate', myHook);
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
#### Rules
|
|
107
|
-
|
|
108
|
-
- all hooks from the same event are running in parallel
|
|
109
|
-
- most of the hooks are asynchronous and are awaited inside router
|
|
110
|
-
- if some error happens when running hook it will be logged to console but wont affect navigation (except for the `beforeResolve` hook - error for it will be rethrown)
|
|
111
|
-
|
|
112
|
-
#### List of available hooks
|
|
113
|
-
|
|
114
|
-
Async hooks:
|
|
115
|
-
|
|
116
|
-
- [navigate hooks](#navigate-hooks) - asynchronous hooks only for navigate calls
|
|
117
|
-
- [updateCurrentRoute hooks](#updatecurrentroute-hooks) - asynchronous hooks only for updateCurrentRoute calls
|
|
118
|
-
|
|
119
|
-
Sync hooks:
|
|
120
|
-
|
|
121
|
-
- `change` - runs when any of changes to current route\url happens
|
|
122
|
-
|
|
123
|
-
## API
|
|
124
|
-
|
|
125
|
-
### Getting data about the current route or url
|
|
126
|
-
|
|
127
|
-
```ts
|
|
128
|
-
router.getCurrentRoute(); // will return the current route
|
|
129
|
-
router.getCurrentUrl(); // will return the parsed version of the url of the current page
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
### Transition initiation
|
|
133
|
-
|
|
134
|
-
There are two methods for initializing the navigation and updating the address bar in the browser. The main difference between these two methods is that one of them will launch a full-fledged transition with data updating and starting heavy data loading actions. The second method is mainly used to update the state for the current route: to update the query parameters on the page or change the dynamic parameters of the route itself.
|
|
135
|
-
|
|
136
|
-
#### navigate
|
|
137
|
-
|
|
138
|
-
Initiates a full transition, defining the next route and updating the state in the browser.
|
|
139
|
-
|
|
140
|
-
```ts
|
|
141
|
-
router.navigate('/test');
|
|
142
|
-
router.navigate({ url: './test', query: { a: '1' } });
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
##### navigate hooks
|
|
146
|
-
|
|
147
|
-
- beforeResolve
|
|
148
|
-
- beforeNavigate
|
|
149
|
-
- afterNavigate
|
|
150
|
-
|
|
151
|
-
##### navigate workflow
|
|
152
|
-
|
|
153
|
-
1. `beforeResolve` hook
|
|
154
|
-
2. [guards](#router-guards)
|
|
155
|
-
3. `beforeNavigate`
|
|
156
|
-
4. `change`
|
|
157
|
-
5. `afterNavigate`
|
|
158
|
-
|
|
159
|
-
#### updateCurrentRoute
|
|
160
|
-
|
|
161
|
-
The transition is based on the current route (therefore this method cannot be called on the server) and allows you to simply update some data for the current page
|
|
162
|
-
|
|
163
|
-
```ts
|
|
164
|
-
router.updateCurrentRoute({ params: { id: 'abc' } });
|
|
165
|
-
router.updateCurrentRoute({ query: { a: '1' } });
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
##### updateCurrentRoute hooks
|
|
169
|
-
|
|
170
|
-
- beforeUpdateCurrent
|
|
171
|
-
- afterUpdateCurrent
|
|
172
|
-
|
|
173
|
-
##### updateCurrentRoute workflow
|
|
174
|
-
|
|
175
|
-
1. `beforeUpdateCurrent`
|
|
176
|
-
2. `change`
|
|
177
|
-
3. `afterUpdateCurrent`
|
|
178
|
-
|
|
179
|
-
### NavigateOptions
|
|
180
|
-
|
|
181
|
-
Object that allows to specify transition options both to [navigate](#navigate) and [updateCurrentRoute](#updatecurrentroute) transitions
|
|
182
|
-
|
|
183
|
-
- `code` - redirect code that is returned on server in case of redirects
|
|
184
|
-
- `navigateState` - any additional data that is stored with route
|
|
185
|
-
|
|
186
|
-
### Working with query
|
|
187
|
-
|
|
188
|
-
#### query option
|
|
189
|
-
|
|
190
|
-
Allows you to set a search string for an url as an object via the `query` option when navigating. The previous query value will be cleared
|
|
191
|
-
|
|
192
|
-
```ts
|
|
193
|
-
router.getCurrentUrl().query; // { с: 'c' }
|
|
194
|
-
|
|
195
|
-
router.navigate({ query: { a: 'a', b: 'b' } });
|
|
196
|
-
router.updateCurrentRoute({ query: { a: 'a', b: 'b' } });
|
|
197
|
-
|
|
198
|
-
router.getCurrentUrl().query; // { a: 'a', b: 'b' }
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
#### preserveQuery
|
|
202
|
-
|
|
203
|
-
Allows you to keep the query value from the current navigation and use them in a new transition
|
|
204
|
-
|
|
205
|
-
```ts
|
|
206
|
-
router.getCurrentUrl().query; // { с: 'c' }
|
|
207
|
-
|
|
208
|
-
router.navigate({ query: { a: 'a' }, preserveQuery: true });
|
|
209
|
-
router.updateCurrentRoute({ query: { a: 'a' }, preserveQuery: true });
|
|
210
|
-
|
|
211
|
-
router.getCurrentUrl().query; // { a: 'a', c: 'c' }
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
If you pass undefined as the value for a specific query key, then this value will be cleared in a new query:
|
|
215
|
-
|
|
216
|
-
```ts
|
|
217
|
-
router.getCurrentUrl().query; // { a: 'a', b: 'b' }
|
|
218
|
-
|
|
219
|
-
router.navigate({ query: { a: undefined, c: 'c' }, preserveQuery: true });
|
|
220
|
-
router.updateCurrentRoute({ query: { a: undefined, c: 'c' }, preserveQuery: true });
|
|
221
|
-
|
|
222
|
-
router.getCurrentUrl().query; // { b: 'b', c: 'c' }
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
### Constructor options
|
|
226
|
-
|
|
227
|
-
- `trailingSlash` - do router should force all urls to end with slash. If `true` - force trailing slash for every path, `false` - force no trailing slash, `undefined` - trailing slash is specified by request and both trailing and not trailing slashes are used. By default value if `undefined`
|
|
228
|
-
- `mergeSlashes` - replace several consecutive slashes by single slashes (slashes after protocol are still be with `//` after protocol name). By default is `false` - no merge for slashes.
|
|
229
|
-
|
|
230
|
-
### Integration with React
|
|
231
|
-
|
|
232
|
-
Library has some useful React hooks and components for working with routing
|
|
233
|
-
|
|
234
|
-
#### useRoute
|
|
235
|
-
|
|
236
|
-
Returns current active route of the application
|
|
237
|
-
|
|
238
|
-
```ts
|
|
239
|
-
import React from 'react';
|
|
240
|
-
import { useRoute } from '@tinkoff/router';
|
|
241
|
-
|
|
242
|
-
export const Component = () => {
|
|
243
|
-
const route = useRoute();
|
|
244
|
-
|
|
245
|
-
return <div>Route path: {route.actualPath}</div>;
|
|
246
|
-
};
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
#### useUrl
|
|
250
|
-
|
|
251
|
-
Returns current active URL of the application
|
|
252
|
-
|
|
253
|
-
```ts
|
|
254
|
-
import React from 'react';
|
|
255
|
-
import { useUrl } from '@tinkoff/router';
|
|
256
|
-
|
|
257
|
-
export const Component = () => {
|
|
258
|
-
const url = useUrl();
|
|
259
|
-
|
|
260
|
-
return <div>Url query: {JSON.stringify(url.query)}</div>;
|
|
261
|
-
};
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
#### useNavigate
|
|
265
|
-
|
|
266
|
-
Creates a callback with a navigation call that can be passed to child components or used as an event handler
|
|
267
|
-
|
|
268
|
-
```ts
|
|
269
|
-
export const Cmp = () => {
|
|
270
|
-
const navigate = useNavigate('/test/');
|
|
271
|
-
|
|
272
|
-
return <div onClick={navigate}>Test</div>;
|
|
273
|
-
};
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
## How to
|
|
277
|
-
|
|
278
|
-
### Load route config from external api
|
|
279
|
-
|
|
280
|
-
Use [transition hook](#transitions-hooks) `beforeResolve` and load routes config based on url.
|
|
281
|
-
|
|
282
|
-
```ts
|
|
283
|
-
router.registerHook('beforeResolve', async (navigation) => {
|
|
284
|
-
const route = await routeResolve(navigation);
|
|
285
|
-
|
|
286
|
-
if (route) {
|
|
287
|
-
router.addRoute(routeTransform(route));
|
|
288
|
-
}
|
|
289
|
-
});
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
### App behind proxy
|
|
293
|
-
|
|
294
|
-
Router doesn't support proxy setup directly. But proxy still can be used with some limitations:
|
|
295
|
-
|
|
296
|
-
- setup proxy server to pass requests to app with rewriting request and response paths. (E.g. for [nginx](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect))
|
|
297
|
-
- it wont work as expected on spa navigation on client, so only option in this case is use the `NoSpaRouter`
|