Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/web-ridge/react-native-ridge-navigation
Simple, performant & type-safe cross platform navigation in React Native / React Native Web
https://github.com/web-ridge/react-native-ridge-navigation
navigation react react-native react-native-web typescript
Last synced: 3 days ago
JSON representation
Simple, performant & type-safe cross platform navigation in React Native / React Native Web
- Host: GitHub
- URL: https://github.com/web-ridge/react-native-ridge-navigation
- Owner: web-ridge
- License: mit
- Created: 2021-07-01T20:48:19.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2024-10-17T21:22:41.000Z (28 days ago)
- Last Synced: 2024-10-31T20:16:51.091Z (14 days ago)
- Topics: navigation, react, react-native, react-native-web, typescript
- Language: TypeScript
- Homepage: https://www.reactnativeridgenavigation.com
- Size: 3.85 MB
- Stars: 112
- Watchers: 4
- Forks: 3
- Open Issues: 11
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
react-native-ridge-navigationSimple and performant navigation on iOS, Android and the web with simple and type-safe api.
Build on top of [grahammendick/navigation](https://github.com/grahammendick/navigation). Check it out if you want more
control over the navigation!## Features
- New architecture (Fabric) ready
- Simple api
- 100% Type safety (routes, params, bottom tabs)
- Bundle splitting (lazy loading, smart prefetching)
- Render as you fetch on iOS, Android & web
- Works on Android, iOS & web!
- Preload data on mouseDown (or more sensitive on hover, see `` example)
- Preload component on hover (on web)
- Automatic deep-linking
- Real-time light/dark mode
- Out of the box scroll restoration (on web), because screens in tab are pushed on top of each other!
- A lot of control over the web layout
- Universal links (already works, but docs need work)
- PWA documentation (already works, but docs need work)## Example
[![Demo of react-native-ridge-navigation](https://drive.google.com/uc?id=1nE0DzlaVza_h3K1KCkPnK5NfIXfYM5c-)](https://www.youtube.com/watch?v=EvNxrRIF7C0)
This is an older video which used react-native-navigation so we have newer material you bottom bar in the meantime :)
View video in better frame [on YouTube](https://www.youtube.com/watch?v=EvNxrRIF7C0)## About us
We want developers to be able to build software faster using modern tools like GraphQL, Golang and React Native.
Give us a follow on Twitter:
[RichardLindhout](https://twitter.com/RichardLindhout),
[web_ridge](https://twitter.com/web_ridge)### Demo
[See example: reactnativeridgenavigation.com](https://www.reactnativeridgenavigation.com/)
### Source
[See source of example app](https://github.com/web-ridge/react-native-ridge-navigation/tree/main/example)
### Register screens
You can register screens with a preload function, the params will be automatically in string format based on the url.
```tsx
// NavigatorRoutes.ts
const PostScreen = registerScreen(
'/post/:id',
lazy(() => import('./PostScreen'),
({ id }) => {
queryClient.prefetchQuery(
queryKeyPostScreen({ id }),
queryKeyPostScreenPromise({ id }),
{ staleTime: 3000 }
);// if you return something here it can be used in the screen itself or somewhere else with
// usePreloadResult(routes.PostScreen)
// in this case react-query handles it based on queryKey so it's not needed but with Relay.dev it is.
// you can put the result of the usePreloadResult in your usePreloadedQuery if you use Relay.dev}
);const routes = {
PostScreen,
// ...
}
export default routes
```## Supported stacks
- normal
- bottomTabsevery screen can be used within every stack. You don't have to configure screens for a stack.
## Installation
#### 1. If you don't have an app yet (optional, but recommended)
Use Expo with prebuild (Expo Go is not supported since we have native libraries)
#### 2. Install deps + library
```
yarn add react-native-ridge-navigation navigation-react-native
```or with npm
```
npm install react-native-ridge-navigation navigation-react-native
```Support for Material You bottom bar in Android
#### 1. add file `expo-plugin-android-material-you-bottom-bar.js` to your root folder
```js
const { withAndroidStyles } = require("@expo/config-plugins");module.exports = function androidMaterialYouBottomBarPlugin(config) {
return withAndroidStyles(config, async (config) => {
const styleFile = config.modResults;
const appTheme = styleFile.resources.style.find(
(style) => style.$.name === 'AppTheme',
);
appTheme.$.parent = 'Theme.Material3.DayNight.NoActionBar';return config;
});
};
```#### 2. add this to your expo config app.config.js or app.json
```json
"plugins": [
"./expo-plugin-android-material-you-bottom-bar"
]
```## Usage
```tsx
import {
createNormalRoot,
createNavigation,
createBottomTabsRoot,
createScreens,
defaultTheme,
} from 'react-native-ridge-navigation';export const NavigationRoots = {
RootHome: 'home',
RootAuth: 'auth',
};// svg to png
// https://webkul.github.io/myscale/
//
// tab icon
// http://nsimage.brosteins.com/Home
export const BottomRoots = {
Posts: {
path: '/post',
title: () => 'Posts',
icon: require('./img/palette-swatch-outline/icon-20.png'),
selectedIcon: require('./img/palette-swatch/icon-20.png'),
child: routes.PostsScreen,
},
Account: {
path: '/account',
title: () => 'Account',
icon: require('./img/account-circle-outline/icon-20.png'),
selectedIcon: require('./img/account-circle/icon-20.png'),
child: routes.AccountScreen,
},
};```
```tsx
// App.tsx
import * as React from 'react';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import AsyncBoundary from './helpers/AsyncBoundary';
import {
createBottomTabsRoot,
createNormalRoot,
NavigationProvider,
} from 'react-native-ridge-navigation';import { BottomRoot, NavigationRoots, screens } from './Navigator';
import routes from './Routes';
import AsyncBoundaryScreen from './helpers/AsyncBoundaryScreen';const navigationRoot = {
[NavigationRoots.RootHome]: createBottomTabsRoot(
[BottomRoot.Home, BottomRoot.Posts, BottomRoot.Account],
{
breakingPointWidth: 500,
components: {
override: HeaderWeb,
},
}
),
[NavigationRoots.RootAuth]: createNormalRoot(routes.AuthScreen),
};export default function App() {
return (
);
}```
See example code for the asyncboundary stuff :)
## New screen
Use the `` component as much as possible since it will work with ctrl+click on the web :)
```tsx
{(linkProps) => (
// or other touchables/buttons
go to post
)}```
## createLinkComponent
Use the `createLinkComponent` component to create re-usable links without render props. E.g to create a linkable button
for react-native-paper```tsx
//ButtonLink.tsx
import { Button } from 'react-native-paper';
import { createLinkComponent } from 'react-native-ridge-navigation';const ButtonLink = createLinkComponent(Button);
export default ButtonLink;
``````tsx
Go further
```
Alternatives (push, replace, refresh or fluent)
```tsx
const { push, replace, refresh, fluent } = useNavigation();// call this where if you can't use
push(routes.PostScreen, {
id: `${item.id}`
});// call this if e.g. after a create you want to go to edit screen
// but without pushing history to the url-stack or app-stack :)
replace(routes.PostScreen, {
id: `${item.id}`
});// call this if you want to refresh the screen with new params
refresh(routes.PostScreen, {
id: `${item.id}`
});// normal root, replace full history
fluent(
fluentRootNormal(NavigationRoots.RootAuth),
fluentScreen(Routes.HomeScreen, {}),
fluentScreen(Routes.PostScreen, { id: '10' }),
fluentScreen(Routes.PostScreen, { id: '20' }),
fluentScreen(Routes.PostScreen, { id: '30' })
);// bottom root, replace full history
fluent(
fluentRootBottomTabs(NavigationRoots.RootHome, BottomRoot.Account),
fluentScreen(Routes.HomeScreen, {}),
fluentScreen(Routes.PostScreen, { id: '10' }),
fluentScreen(Routes.PostScreen, { id: '20' }),
fluentScreen(Routes.PostScreen, { id: '30' })
);
```## Switch root
Switch root can be used to switch from e.g. the auth screen to a different entrypoint of your app. E.g. check the role
and switch the stacks to different roots for different user roles.```tsx
;
// or e.g.
;
```## useNavigation
All available properties
```tsx
const {
pop, // go back
switchRoot,
preload, // call preload (done automatic on link mouseDown
push, // calls preload + pushes screen
replace, // calls preload + replaces screen
refresh, // calls preload + replaces params of screen
} = useNavigation()
```## Control bottom tabs
```tsx
const { switchToTab, currentTab } = useBottomTabIndex();
const { updateBadge, badges } = useBottomTabBadges();
// updateBadge(BottomRoots.Projects, '10');
// switchToTab(BottomRoot.Posts);
```## Modal stack
If you want a nested stack e.g. in a modal, check out
the [example code](https://github.com/web-ridge/react-native-ridge-navigation/blob/main/example/src/Account/AccountScreen.tsx)
.```tsx
import {
NavigationNestedProvider,
ModalBackHandler,
} from 'react-native-ridge-navigation';{(handleBack) => (
{
if (!handleBack()) setModalVisible(false);
}}
>
{/* you can render your children here and push to all registered screens*/}
Close modal
{(linkProps) => Account}
)}```
## Deep linking
You have to enable url schemes etc in your app and it'll work!
If you want to deep link into a bottom tab or other screen you can use the fluent navigation in development mode and it will log the required url to go to the right screen :)
## More
```ts
// global
createLinkComponent,
SwitchRoot,
BottomTabLink,
Link
BackLink // for now .pop() but we'll update this according to Android guidelines later on (to always go back in hierarchy)
lazyWithPreload // only available on the web: see example app
Redirect,
StatusBar,
FocusAwareStatusBar,
NavigationRoot,
createNavigation,
createBottomTabsRoot,
createNormalRoot,
registerScreen,
createScreens,
defaultTheme,
setTheme,
getTheme,
createSimpleTheme,
setPreloadResult, // should not need this as it is done automatically// common hooks
useParams,
useNavigation,// extra
useBottomTabIndex,
useBottomTabBadges,
useBottomTabRefresh,
useTheme,
useIsFocused,
useFocus,// same as useNavigating
useNavigating,
useNavigated,
useUnloaded,
usePreloadResult // e.g. usePreloadResult(routes.PostScreen)
```## Do global stuff like updating badge
If you want to use a component globally with the navigation context pass them as children of the NavigationProvider
```tsx
```
# Scroll fix on web version
On the web version we need to disable window scroll since else it will sometimes use windows scroll instead of the
scrollview Add this to your css```css
body {
overflow: hidden;
}
```## Contributing
See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
## License
MIT
### Checkout our other libraries
- Simple form library for React Native with great UX for developer and
end-user [react-native-use-form](https://github.com/web-ridge/react-native-use-form)
- Smooth and fast cross platform Material Design date and time picker for React Native
Paper: [react-native-paper-dates](https://github.com/web-ridge/react-native-paper-dates)
- Smooth and fast cross platform Material Design Tabs for React Native
Paper: [react-native-paper-tabs](https://github.com/web-ridge/react-native-paper-tabs)- Simple translations in React (
Native): [react-ridge-translations](https://github.com/web-ridge/react-ridge-translations)
- Simple global state management in React (Native): [react-ridge-state](https://github.com/web-ridge/react-ridge-state)