Next.js App Router
Solito supports the Next.js App Router as of v4. Keep in mind that React Native Web components are all client components, so you will likely find yourself using use client
often.
How it works​
Solito introduces a number of changes in v4 to support the App Router. All previous code and docs still work with pages
. However, you will need to use the new hooks from solito/navigation
to access the router and URL parameters.
solito/link
​
Link
and TextLink
components are now marked with use client
, making them compatible with RSC and the App Router.
solito/image
​
SolitoImage
is now marked with use client
, making it compatible with RSC and the App Router.
solito/moti
​
To use the MotiLink
component in the App Directory, you should import it from solito/moti/app
.
solito/navigation
​
Following the Next.js approach, there is now a new import, solito/navigation
, for the App Router hooks. You will use this instead of other imports you may be used to, such as solito/router
for useRouter
.
The following hooks are added:
useRouter
: Similar to theuseRouter
hook fromsolito/router
, adapted for the App Router by following thenext/navigation
conventions. It has the same behavior on iOS and Android.useParams
: Read dynamic segment parameters (/users/[userId]
) as{ userId: string }
.useSearchParams
: Read URL search parameters using theURLSearchParams
class.usePathname
: The much-requested hook to read the current path. On native, this is only safe if you're using Expo Router. This hook may change in the future, depending on its stability on native.useUpdateSearchParams
: A convenience hook to update search parameters as an object. CallssetParams
on native, androuter.push
orrouter.replace
on Web (configurable).useLink
The same hook that exists now fromsolito/link
, adapted for the App Router. You can call this to create accessible, custom link components.
Setup​
In addition to using new code, you'll need to add some configurations to the root layout component in the app
folder.
/app/layout.tsx
​
Clear out the layout.tsx
file to look like this:
tsx
import { StylesProvider } from './styles-provider'import './globals.css'export const metadata = {title: 'Create Solito App',description: 'Generated by create Solito app',}export default function RootLayout({children,}: {children: React.ReactNode}) {return (<html lang="en"><body><StylesProvider>{children}</StylesProvider></body></html>)}
tsx
import { StylesProvider } from './styles-provider'import './globals.css'export const metadata = {title: 'Create Solito App',description: 'Generated by create Solito app',}export default function RootLayout({children,}: {children: React.ReactNode}) {return (<html lang="en"><body><StylesProvider>{children}</StylesProvider></body></html>)}
Notice that we have two imports at the top. Let's implement those next.
/app/styles-provider.tsx
​
StylesProvider
should look like this (you can copy-paste it):
Click to view code
tsx
// @ts-nocheck'use client'import { useServerInsertedHTML } from 'next/navigation'import { StyleSheet } from 'react-native'export function StylesProvider({ children }: { children: React.ReactNode }) {useServerInsertedHTML(() => {const sheet = StyleSheet.getSheet()return (<styledangerouslySetInnerHTML={{ __html: sheet.textContent }}id={sheet.id}/>)})return <>{children}</>}
tsx
// @ts-nocheck'use client'import { useServerInsertedHTML } from 'next/navigation'import { StyleSheet } from 'react-native'export function StylesProvider({ children }: { children: React.ReactNode }) {useServerInsertedHTML(() => {const sheet = StyleSheet.getSheet()return (<styledangerouslySetInnerHTML={{ __html: sheet.textContent }}id={sheet.id}/>)})return <>{children}</>}
/app/globals.css
​
Finally, add this CSS reset:
Click to view code
css
html,body,#__next {width: 100%;/* To smooth any scrolling behavior */-webkit-overflow-scrolling: touch;margin: 0px;padding: 0px;/* Allows content to fill the viewport and go beyond the bottom */min-height: 100%;}#__next {flex-shrink: 0;flex-basis: auto;flex-direction: column;flex-grow: 1;display: flex;flex: 1;}html {scroll-behavior: smooth;/* Prevent text size change on orientation change https://gist.github.com/tfausak/2222823#file-ios-8-web-app-html-L138 */-webkit-text-size-adjust: 100%;height: 100%;}body {display: flex;/* Allows you to scroll below the viewport; default value is visible */overflow-y: auto;overscroll-behavior-y: none;text-rendering: optimizeLegibility;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;-ms-overflow-style: scrollbar;}
css
html,body,#__next {width: 100%;/* To smooth any scrolling behavior */-webkit-overflow-scrolling: touch;margin: 0px;padding: 0px;/* Allows content to fill the viewport and go beyond the bottom */min-height: 100%;}#__next {flex-shrink: 0;flex-basis: auto;flex-direction: column;flex-grow: 1;display: flex;flex: 1;}html {scroll-behavior: smooth;/* Prevent text size change on orientation change https://gist.github.com/tfausak/2222823#file-ios-8-web-app-html-L138 */-webkit-text-size-adjust: 100%;height: 100%;}body {display: flex;/* Allows you to scroll below the viewport; default value is visible */overflow-y: auto;overscroll-behavior-y: none;text-rendering: optimizeLegibility;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;-ms-overflow-style: scrollbar;}
That's it!
_document.tsx
/_app.tsx
​
You can start using the App Router with Solito without changing those existing files.
Follow the Next.js Docs​
Please reference the official Next.js docs for using the App Router.
Example​
Here is a minimal repo with the App Directory and React Native Web to reference. It is not a starter app necessarily.