Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(router): ENG-5727 router impl #2757

Merged

Conversation

crherman7
Copy link
Contributor

@crherman7 crherman7 commented Sep 16, 2024

Describe your changes

Add implementation of routing solution as thin-client around react-native-navigation.

  • path based routing (bottom tab + component + action)
  • route guards
  • bottom tab + single stack layout
  • route context hooks
  • native modals
  • tab-affinity
  • global provider
  • pre-launch script

Issue ticket number and link

Ticket ENG-5727
Ticket ENG-5728
Ticket ENG-5729
Ticket ENG-5730

Type of change

  • New feature (non-breaking change which adds functionality)

Test Plan

Run the example app.

Checklist before requesting a review

  • A self-review of my code has been completed
  • Tests have been added / updated if required

@crherman7 crherman7 marked this pull request as draft September 16, 2024 19:36
@NickBurkhartBB NickBurkhartBB changed the base branch from develop to feature/app-router September 16, 2024 21:53
@crherman7 crherman7 force-pushed the feat/ENG-5727 branch 2 times, most recently from 406700b to 1d3de35 Compare September 24, 2024 18:42
@crherman7 crherman7 changed the title feat(router): ENG-5727 router register routes feat(router): ENG-5727 router impl Sep 24, 2024
if (!Component) return;

// Attach options to the component
(Component as any).options = passOptions;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deep merge with static options

@crherman7 crherman7 marked this pull request as ready for review September 25, 2024 14:06
packages/app-router/src/router.tsx Outdated Show resolved Hide resolved
packages/app-router/src/router.tsx Outdated Show resolved Hide resolved
packages/app-router/src/router.tsx Outdated Show resolved Hide resolved
// handle the error (e.g., log it)
}

Navigation.setRoot(layout);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we may want to separate the registration of routes and setting the layout. Having this way reduces flexibility for any app that needs some type of conditional root based on whatever data and would require patch to allow them to use this library.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this, this would be important for conditional layouts. We should likely add an additional optional parameter called autoRoot or autoLayout - which will default to true. If it is false it will then not setRoot and either way it will resolve the created layout that would be used in setRoot based on the routes supplied.

packages/app-router/src/hooks.tsx Outdated Show resolved Hide resolved
async function open(path: string, passProps = {}, options?: Options) {
const url = createAppURL(path);
const matchedRoute = route.routes.find(it => {
return match(it.path)(url.pathname);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this may be premature optimization, but should we have this path-to-regexp run once in register routes setup, not through every search loop?

packages/app-router/src/hooks.tsx Outdated Show resolved Hide resolved
packages/app-router/src/hooks.tsx Outdated Show resolved Hide resolved
packages/app-router/src/hooks.tsx Outdated Show resolved Hide resolved
packages/app-router/src/hooks.tsx Outdated Show resolved Hide resolved
layout: LayoutRoot,
routeName: string,
bottomTab: any,
stackId?: string,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stackId is not described in JSDoc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice catch, updated!


/**
* Renders the component for a given route.
*
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: wrong JSDoc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice catch, updated!


/**
* Registers a single route with the navigation system.
*
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: wrong JSDoc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice catch, updated!


/**
* Registers routes and sets the root layout for the application.
*
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: wrong JSDoc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice catch, updated!

Comment on lines 486 to 487
const name = `Modal_${idCounter}`;
idCounter++;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it might also be useful to optionally pass this nane as we do for route

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this - but it needs more thought because we won't know for sure if the "screen" has been registered or not.

@devs9
Copy link

devs9 commented Nov 3, 2024

I like this router implementation ❤️
especially the single stack layout, route guards, and providers great features 👍

packages/app-router/src/router.tsx Outdated Show resolved Hide resolved
packages/app-router/src/types.ts Outdated Show resolved Hide resolved
packages/app-router/src/router.tsx Outdated Show resolved Hide resolved
Here's a brief overview of each hook:

1. `useComponentId` - This hook allows you to get the unique component ID from the current route.
2. `useLinking` - This hook provides functionality for linking between routes in your application.
3. `useModal` - This hook manages modals within your application, allowing you to open and close them as needed.
4. `useNavigator` - This hook provides a way to navigate through the application's history.
5. `usePathParams` - This hook allows you to access the dynamic path parameters from the current route.
6. `useQueryParams` - This hook enables you to access the query parameters from the current URL.
7. `useRoute` - This hook retrieves the current router state from the RouterContext.
8. `useRouteData` - This hook allows you to retrieve the router data associated with the current route.
export function useRouteData<T>(): T {
const route = useRoute();

return route.data as T;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does this add above useRoute? seems like you just get less information using this hook and could just use useRoute.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I don't like this hook either, was trying to preserve previous interface from fsapp


callback({url});
} catch (e) {
// Handle the error (e.g., log it)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rather then eating this errors without any ways of modification other then patch, do you think we should add an optional handler callback function to be passed into useLinking? that way if they have custom logging around errors they could add it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah probably some kind of callback would be good, good idea.


try {
Navigation.registerComponent(
name,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if registering this component each time on show modal has a consequence of flooding the registry and causing memory issues. maybe we should keep this in mind and run a stress test in an application around this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I was thinking same thing before, I'm going to test to see about a tagging policy....that way if the component is tagged we can just render.

if (!url) return;

try {
const {pathname, query} = urlParse(url);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to use hostname in deep links as well. I am seeing examples of apps using deep links like app-name://shop and expecting it to route to path /shop. but since shop is the host based on urlParse the path doesn't match. example in docs would route path ?user=123 instead of /profile?user=123. not sure if we want to just check protocol or have a way to customize.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so I don't think we are aligned on this, I may be miss-reading this. but this hook would only be triggered by a host that is registered natively via info.plist or manifest. can you elaborate further? maybe this conversation belongs in the open function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After talking on the call the main issues surrounds how url-parse parses a provided URL.

https://www.google.com/search?id=abc

host -> www.google.com
path -> /search
myapp://app/search?id=abc

host -> app
path -> /search

This may cause issues depending on how the url scheme is registered and how the routes are defined. If there is no host defined in the url schemes then the path should be /app/search where is if the host is defined as app and the routes do not start with /app then the path would be /search. So we need to come up with logic that fills these parameters.

packages/app-router/src/hooks.tsx Outdated Show resolved Hide resolved
@crherman7 crherman7 force-pushed the feat/ENG-5727 branch 2 times, most recently from 64597cc to 3529712 Compare November 14, 2024 15:38
@NickBurkhartBB NickBurkhartBB merged commit 64bf3c9 into brandingbrand:feature/app-router Nov 18, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants