Ray
Ray

Reputation: 71

Use stack layout as expo-router slot child route

I am currently using expo router 2 with expo SDK49.

I would like to add a child route of a slot layout to be rendered as a stack layout - ie whole screen replaced with a back button. I can't seem to make it work and I can't seem to find anything in the docs.

I've produced a minimum example, attached below.

Any help would be appreciated.

Project structure

app
├── _layout.tsx
├── index.jsx
├── meow
│   └── test.tsx
└── woof
    ├── _layout.tsx
    └── test.tsx

app/_layout.tsx

import { View, Text } from 'react-native'
import React from 'react'
import { Slot, Link } from 'expo-router'
import { SafeAreaView } from 'react-native-safe-area-context'

const Layout = () => {
  return (
    <SafeAreaView style={{flex: 1}}>
      <Header />
      <Slot />      
    </SafeAreaView>

  )
}

const Header = () => {
  return (
    <View style={{flex: 1}}> 
      <Text> Header </Text>
      <Link href='/meow/test' asChild>
        <Text> Click here to render meow into slot </Text>
      </Link>
    </View>
  )
}

export default Layout

app/index.jsx

import { View, Text } from 'react-native'
import React from 'react'

const Page = () => {
  return (
    <View>
      <Text>Hello world</Text>
    </View>
  )
}

export default Page

meow/test.tsx

import { View, Text } from 'react-native'
import React from 'react'
import { Link } from 'expo-router'

const Page = () => {
  return (
    <View>
      <Text>I am at meow, in a slot.</Text>
      <Link href='/woof/test'>
        <Text>Going to woof, should be a stack.</Text>
      </Link>
    </View>
  )
}

export default Page

woof/_layout.tsx

import { View, Text } from 'react-native'
import React from 'react'
import { Stack } from 'expo-router'

const Layout = () => {
  return (
    <Stack />
  )
}

export default Layout

woof/test.tsx

import { View, Text } from 'react-native'
import React from 'react'

const Page = () => {
  return (
    <View>
      <Text>This is supposed to be a stack child!</Text>
    </View>
  )
}

export default Page

Here are the screenshots of each screen:

Initial screen on app open

Clicked on meow, rendered into slot

From meow to woof with a stack layout but rendered into slot

I've also tried having a meow/_layout.tsx with a Stack layout which doesn't work either.

Is it even possible to do what I am trying to do with Slot? If not, are there any workarounds?

Thanks in advance,

Upvotes: 7

Views: 4941

Answers (1)

resin-code
resin-code

Reputation: 26

I am currently using Expo SDK 51 and I encountered the same issue. I had to intervene with react-navigation components. It worked as I wanted, but there are some differences. The stacks I created are added to the native stack, not Expo's stack. Even though these stacks are child stacks of Expo's stack, I was able to add them to the stack by using navigate('new-native-stack').

Here is the relevant code:

_layout.tsx

import { View, Text, Button } from 'react-native';
import React from 'react';
import { Slot, Stack, useNavigation } from 'expo-router';
import HomeHeader from '@/components/HomeHeader';
import { SafeAreaView } from 'react-native-safe-area-context';

type Props = {};

type MainScreenContext = {};

const MainScreenContext = React.createContext<MainScreenContext>({});

const Layout = (props: Props) => {
    const navigation = useNavigation();

    return (
        <>
            
                <HomeHeader />
                <Slot />
            
        </>
    );
}

export default Layout;

A normal Expo stack under the layout

import { createNativeStackNavigator } from '@react-navigation/native-stack';
import React from 'react';
import ChatsScreen from './ChatsScreen';
import SearchScreen from './SearchScreen';

type Props = {};
const Stack = createNativeStackNavigator();

const Layout = (props: Props) => {
    return (
        <Stack.Navigator initialRouteName="chats">
            <Stack.Screen
                name="search"
                options={{
                    headerShown: false,
                    animation: 'none',
                }}
                component={SearchScreen}
            />
            <Stack.Screen
                name="chats"
                options={{
                    headerShown: false,
                    animation: 'none',
                }}
                component={ChatsScreen}
            />
        </Stack.Navigator>
    );
}

export default Layout;


Now these two SearchScreen and ChatsScreen are stacks. When I go from chats to search, it pushes as a new stack. Chats will not unmount.

For this example, I navigate between these two screens in my HomeHeader.

Upvotes: 1

Related Questions