I'm going to jot down some thoughts about what navigation should look like. Feedback welcome.
There are a few different concepts to deal with:
- Getting around from one "page" to another
- Opening "modals" which don't take you to another "page"
- Knowing what to display
1. Getting around from one page to another
I've found that the most elegant solution to get around an app is a URL. Instead of navigate('artists'), we should do linkTo('/artists').
For native, in our linking.config, we define all the mappings of URL → state. On web, we leave linking={undefined}, and defer to Next file system routing for getting around from page-to-page.
2. Modals 😱
This is a tricky one. Sometimes, modals should be reflected in URLs. But maybe there are cases where they shouldn't.
Here's the solution I think could work. Create a web-only modal stack per Next.js page. The modal should show based on the URL. Example in this tweet.
Each "modal" (which is technically a screen) would pop on top of the base screen, depending on the URL. This is all handled by Next.js' shallow routing. To close it, you just goBack. Meanwhile, on native, you just use stackPresentation: 'modal' with the native-stack.
Caveats
Are there times when you want to open modals but not change the URL? Presumably you could "shallow" route to the current pathname on web using as, but then it won't deep link there on native. I guess that's fine. Need to give it some thought.
3. What to display
React Navigation handles this on native elegantly.
On web, next router does too. Except for modals. My current method was to make a react-navigation stack per Next.js page on web. For my native-stack, I use the same screens, and make sure to give them the same name. Holy shit is that a fragile approach. Luckily TypeScript ensures that I use the same screen names (I guess), but I really don't like it. URLs are much more reliable IMO.
What's next
I think all APIs should be consolidated into URLs. Stacks on web should render per-page based on the URL. This helps with code splitting too, I suppose.
On native, you should have a single native-stack that has all of your screens. You should use linking.config to map URL → screen. If you need to push multiple of the same screen on top of each other, you should use the getId field on react-navigation's <Stack.Screen /> component.
We should get around from page-to-page like so:
<Link to="/artists/djkhaled"></Link>
// or
linkTo('/artists/djkhaled')
We can open modals like so.
openModal('edit') // this needs intellisense!
Now that I think about it, maybe opening modals should be constrained to URLs too. The only problem is, they're less typed.
Maybe it should be this?
linkTo('/artists/djkhaled/edit')
Oof, I don't know. This is hard.
What about query parameters?
There needs to be a better abstraction for using query parameters as state.
I often want to do this:
beatgig.com/search?query=djkhaled
I end up creating a useQuery.web.ts that uses the URL params on web, and local state on native. Don't love that approach. We need something more standardized.
I'm going to jot down some thoughts about what navigation should look like. Feedback welcome.
There are a few different concepts to deal with:
1. Getting around from one page to another
I've found that the most elegant solution to get around an app is a URL. Instead of
navigate('artists'), we should dolinkTo('/artists').For native, in our
linking.config, we define all the mappings of URL → state. On web, we leavelinking={undefined}, and defer to Next file system routing for getting around from page-to-page.2. Modals 😱
This is a tricky one. Sometimes, modals should be reflected in URLs. But maybe there are cases where they shouldn't.
Here's the solution I think could work. Create a web-only modal stack per Next.js page. The modal should show based on the URL. Example in this tweet.
Each "modal" (which is technically a screen) would pop on top of the base screen, depending on the URL. This is all handled by Next.js' shallow routing. To close it, you just
goBack. Meanwhile, on native, you just usestackPresentation: 'modal'with thenative-stack.Caveats
Are there times when you want to open modals but not change the URL? Presumably you could "shallow" route to the current
pathnameon web usingas, but then it won't deep link there on native. I guess that's fine. Need to give it some thought.3. What to display
React Navigation handles this on native elegantly.
On web, next router does too. Except for modals. My current method was to make a
react-navigationstack per Next.js page on web. For mynative-stack, I use the same screens, and make sure to give them the samename. Holy shit is that a fragile approach. Luckily TypeScript ensures that I use the same screen names (I guess), but I really don't like it. URLs are much more reliable IMO.What's next
I think all APIs should be consolidated into URLs. Stacks on web should render per-page based on the URL. This helps with code splitting too, I suppose.
On native, you should have a single
native-stackthat has all of your screens. You should uselinking.configto map URL → screen. If you need topushmultiple of the same screen on top of each other, you should use thegetIdfield on react-navigation's<Stack.Screen />component.We should get around from page-to-page like so:
We can open modals like so.
Now that I think about it, maybe opening modals should be constrained to URLs too. The only problem is, they're less typed.
Maybe it should be this?
Oof, I don't know. This is hard.
What about query parameters?
There needs to be a better abstraction for using query parameters as state.
I often want to do this:
I end up creating a
useQuery.web.tsthat uses the URL params on web, and local state on native. Don't love that approach. We need something more standardized.