mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-04-28 20:35:19 +08:00
feat: make deep link handling more flexible
This adds ability to specify a custom config to control how to convert between state and path.
Example:
```js
{
Chat: {
path: 'chat/:author/:id',
parse: { id: Number }
}
}
```
The above config can parse a path matching the provided pattern: `chat/jane/42` to a valid state:
```js
{
routes: [
{
name: 'Chat',
params: { author: 'jane', id: 42 },
},
],
}
```
This makes it much easier to control the parsing without having to specify a custom function.
This commit is contained in:
committed by
Satyajit Sahoo
parent
17045f5b6d
commit
849d952703
@@ -7,6 +7,12 @@ import {
|
||||
PartialState,
|
||||
} from '@react-navigation/core';
|
||||
|
||||
type Config = {
|
||||
[routeName: string]:
|
||||
| string
|
||||
| { path: string; parse?: { [key: string]: (value: string) => any } };
|
||||
};
|
||||
|
||||
type Options = {
|
||||
/**
|
||||
* The prefixes are stripped from the URL before parsing them.
|
||||
@@ -14,27 +20,44 @@ type Options = {
|
||||
*/
|
||||
prefixes: string[];
|
||||
/**
|
||||
* Custom function to parse the URL object to a valid navigation state.
|
||||
* Config to fine-tune how to parse the path.
|
||||
*
|
||||
* Example:
|
||||
* ```js
|
||||
* {
|
||||
* Chat: {
|
||||
* path: 'chat/:author/:id',
|
||||
* parse: { id: Number }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
config?: Config;
|
||||
/**
|
||||
* Custom function to parse the URL object to a valid navigation state (advanced).
|
||||
*/
|
||||
getStateFromPath?: (
|
||||
path: string
|
||||
path: string,
|
||||
options?: Config
|
||||
) => PartialState<NavigationState> | undefined;
|
||||
};
|
||||
|
||||
export default function useLinking(
|
||||
ref: React.RefObject<NavigationContainerRef>,
|
||||
{ prefixes, getStateFromPath = getStateFromPathDefault }: Options
|
||||
{ prefixes, config, getStateFromPath = getStateFromPathDefault }: Options
|
||||
) {
|
||||
// We store these options in ref to avoid re-creating getInitialState and re-subscribing listeners
|
||||
// This lets user avoid wrapping the items in `React.useCallback` or `React.useMemo`
|
||||
// Not re-creating `getInitialState` is important coz it makes it easier for the user to use in an effect
|
||||
const prefixesRef = React.useRef(prefixes);
|
||||
const configRef = React.useRef(config);
|
||||
const getStateFromPathRef = React.useRef(getStateFromPath);
|
||||
|
||||
React.useEffect(() => {
|
||||
prefixesRef.current = prefixes;
|
||||
configRef.current = config;
|
||||
getStateFromPathRef.current = getStateFromPath;
|
||||
}, [getStateFromPath, prefixes]);
|
||||
}, [config, getStateFromPath, prefixes]);
|
||||
|
||||
const extractPathFromURL = React.useCallback((url: string) => {
|
||||
for (const prefix of prefixesRef.current) {
|
||||
@@ -51,7 +74,7 @@ export default function useLinking(
|
||||
const path = url ? extractPathFromURL(url) : null;
|
||||
|
||||
if (path) {
|
||||
return getStateFromPathRef.current(path);
|
||||
return getStateFromPathRef.current(path, configRef.current);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
@@ -63,7 +86,7 @@ export default function useLinking(
|
||||
const navigation = ref.current;
|
||||
|
||||
if (navigation && path) {
|
||||
const state = getStateFromPathRef.current(path);
|
||||
const state = getStateFromPathRef.current(path, configRef.current);
|
||||
|
||||
if (state) {
|
||||
navigation.resetRoot(state);
|
||||
|
||||
Reference in New Issue
Block a user