React-navigation switch theme toggle - javascript

i've implemented theming support into my app with react-navigation, as you can see below.
i am using the system theme settings, and my app follows this rule
this is working great, but there's one thing left on my to-do list,
a option to toggle light/dark theme inside my app,
keep this selection, and store it into the user defaults or something like that..
i followed the official docs (https://reactnavigation.org/docs/themes/)
but they don't mention how to switch themes manually.
in my testing i always got a message that the theme prop is read only and cannot be changed manually.
so how to do that?
any help'd be greatly appreciated ;)
App.js
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { AppearanceProvider, useColorScheme, useTheme } from 'react-native-appearance';
const Stack = createStackNavigator();
// ------------------App-----------------------------
export default function App() {
const scheme = useColorScheme();
const MyDarkTheme = {
dark: true,
...},
const LightTheme = {
dark: false,
...}
return (
<AppearanceProvider>
<NavigationContainer theme={scheme === "dark" ? MyDarkTheme : LightTheme}>
<Stack.Navigator>
<Stack.Screen>
name="home"
...
<Stack.Screen
name="Settings"
component={Settings}
/>
</Stack.Navigator>
</NavigationContainer>
</AppearanceProvider>
);
}
in my Components:
import React, { useState, useEffect} from 'react';
import { Card } from 'react-native-elements';
import { useTheme} from '#react-navigation/native';
function CardOne(props) {
const { colors } = useTheme(); // works
const theme = useTheme();
return (
<Card containerStyle={{backgroundColor: colors.cardBackgroundColor, borderColor: colors.borderColor, borderWidth: 2, borderRadius: 5}}>
...
</Card>
);
}
export default CardOne;
i really someone can help me out ;)

You can use the Context and do something like below, basically maintain the theme in state at App.js and update value via context.
export const ThemeContext = React.createContext();
export default function App() {
const [theme, setTheme] = useState('Light');
const themeData = { theme, setTheme };
return (
<ThemeContext.Provider value={themeData}>
<NavigationContainer theme={theme == 'Light' ? DefaultTheme : DarkTheme}>
<Drawer.Navigator initialRouteName="Root">
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Root" component={Root} />
</Drawer.Navigator>
</NavigationContainer>
</ThemeContext.Provider>
);
}
You can switch the theme from a screen like below
function ProfileScreen({ navigation }) {
const { setTheme, theme } = React.useContext(ThemeContext);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Profile Screen</Text>
<Button
title="Switch Theme"
onPress={() => setTheme(theme === 'Light' ? 'Dark' : 'Light')}
/>
</View>
);
}
Sample code
https://snack.expo.io/#guruparan/5b84d0

Related

How can i modify the header structure of Drawer Navigator, taking into account that each screen will have a different header?

import * as React from "react";
import { SafeAreaView, useWindowDimensions } from "react-native";
import { createDrawerNavigator } from '#react-navigation/drawer';
import { NavigationContainer } from "#react-navigation/native";
import { RegistrationScreen } from './src/screens/Registration/RegistrationScreen';
import {LoginScreen} from './src/screens/Login/LoginScreen';
import {NewAnuncioScreen} from './src/screens/NewAnuncio/NewAnuncioScreen';
import { FeedScreen } from "./src/screens/Feed/FeedScreen";
import { FontAwesome, AntDesign, FontAwesome5, Entypo} from '#expo/vector-icons';
const Drawer = createDrawerNavigator()
const App = () => {
const dimensions = useWindowDimensions();
return (
<SafeAreaView style={{ flex: 1 }}>
<NavigationContainer>
<Drawer.Navigator initialRouteName="Feed" screenOptions={{
headerStyle: { backgroundColor: "#f2bc1b" , height: 55},
drawerType: dimensions.width >= 821 ? 'permanent' : 'front',
overlayColor: 'transparent',
drawerContent:{CustomDrawerContent}
}}>
<Drawer.Screen name="Feed" component={FeedScreen}/>
<Drawer.Screen name="Registration" component={RegistrationScreen} options={{ headerShown: false }} />
<Drawer.Screen name="Login" component={LoginScreen} options={{ headerShown: false }} />
{/* <Drawer.Screen name="Criar Anúncio" component={NewAnuncioScreen} /> */}
</Drawer.Navigator>
</NavigationContainer>
</SafeAreaView>
)
}
export default App;
**I want the header´s structures can vary like that:
enter image description here
enter image description here
But i don´t know how to make this.
If someone help me i thanks.**
You should pass the Drawer props to your custom drawer and retrieve the navigation index.
drawerContent = {(props) => <CustomDrawerContent {...props} />}
Then
const CustomDrawerContent = (props) => {
const [index, setIndex] = useState(0)
useEffect(() => {
setIndex(props.state.index);
}, [props])
...
Now according to this index you can change the appearance and the behavior your drawer content.

How can i add a navigation drawer inside a stack navigator in an already existing project

Hello guys so I wanted to add a navigation DRAWER inside my main screen and I did not know how to nest it with the already existing stack navigator ,
this is my navigation component :
import React from "react";
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
import ProductsOverviewScreen from "../screens/shop/ProductsOverviewScreen";
import ProductDetails from "../screens/shop/ProductDetailScreen";
import { HeaderButtons,Item } from "react-navigation-header-buttons";
import HeaderButton from '../components/UI/HeaderButton'
import CartScreen from "../screens/shop/CartScreen";
import OrdersScreen from "../screens/shop/OrdersScreen";
const RootNavigation=()=> {
const Stack = createStackNavigator();
const NavigationDrawerStructure = (props)=> {
//Structure for the navigatin Drawer
const toggleDrawer = () => {
//Props to open/close the drawer
props.navigationProps.toggleDrawer();
};
return (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity onPress={()=> toggleDrawer()}>
{/*Donute Button Image */}
<Image
source={{uri: 'https://raw.githubusercontent.com/AboutReact/sampleresource/master/drawerWhite.png'}}
style={{ width: 25, height: 25, marginLeft: 5 }}
/>
</TouchableOpacity>
</View>
);
}
const screenOptions ={
headerShown:true,
headerStyle: {
backgroundColor: 'white',},
headerTintColor: 'aqua',
headerTitleStyle: {
fontWeight: 'bold',
},
};
return(
<NavigationContainer>
<Stack.Navigator initialRouteName='ProductsOverview' screenOptions={screenOptions}>
<Stack.Screen name='ProductsOverview' component={ProductsOverviewScreen} options={({navigation,route})=>({title:'All Products',headerTitleStyle:{fontFamily:'open-sans-bold'},
headerRight:()=>( <HeaderButtons HeaderButtonComponent={HeaderButton}><Item title ='Cart' iconName='md-cart' onPress={()=>{navigation.navigate('CartScreen')}}/></HeaderButtons>)})}/>
<Stack.Screen name='ProductsDetail' component={ProductDetails} options={({route})=>({title:route.params.productTitle,headerTitleStyle:{fontFamily:'open-sans-bold'}})} />
<Stack.Screen name='CartScreen' component={CartScreen} options={{title:'Cart Items', headerTitleStyle:{fontFamily:'open-sans-bold'}}} />
<Stack.Screen name='OrdersScreen' component={OrdersScreen} options={{title:'Orders '}}/>
</Stack.Navigator>
</NavigationContainer>
)
}
export default RootNavigation;
and this is my app.js
import { StatusBar } from 'expo-status-bar';
import { StyleSheet } from 'react-native';
import {createStore , combineReducers} from 'redux';
import { Provider} from 'react-redux';
import AppLoading from 'expo-app-loading';
import * as Font from 'expo-font';
import productsReducer from './store/reducers/products';
import {composeWithDevTools} from 'redux-devtools-extension'
import RootNavigation from './navigation/ShopNavigation';
import cartReducer from './store/reducers/cart'
import { useState } from 'react';
import ordersReducer from './store/reducers/orders'
const rootReducer=combineReducers({
products: productsReducer,
cart: cartReducer,
orders:ordersReducer,
});
const store = createStore(rootReducer,composeWithDevTools());
const fetchFonts=()=>{
return Font.loadAsync({
'open-sans': require('./assets/fonts/OpenSans-Regular.ttf'),
'open-sans-bold': require('./assets/fonts/OpenSans-Bold.ttf')
})
}
export default function App() {
const [fontLoaded,setfontLoaded]= useState(false);
if (!fontLoaded) {
return (
<AppLoading
startAsync={fetchFonts}
onFinish={()=>setfontLoaded(true)}
onError={console.warn}
/>
);
}
return (
<Provider store={store}>
<RootNavigation />
</Provider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
can you give me an idea how to nest them together I tried using the docs but still full of errors
and Thanks
Drawer Navigator must be a parent to both Stack and Tab navigators. With that knowledge, let we refactor our code as below:
import React from "react";
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
import ProductsOverviewScreen from "../screens/shop/ProductsOverviewScreen";
import ProductDetails from "../screens/shop/ProductDetailScreen";
import { HeaderButtons, Item } from "react-navigation-header-buttons";
import HeaderButton from "../components/UI/HeaderButton";
import CartScreen from "../screens/shop/CartScreen";
import OrdersScreen from "../screens/shop/OrdersScreen";
import { createDrawerNavigator } from "#react-navigation/drawer";
const RootNavigation = () => {
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const AppStack = () => (
<Stack.Navigator
initialRouteName="ProductsOverview"
screenOptions={screenOptions}
>
<Stack.Screen
name="ProductsOverview"
component={ProductsOverviewScreen}
options={({ navigation, route }) => ({
title: "All Products",
headerTitleStyle: { fontFamily: "open-sans-bold" },
headerRight: () => (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title="Cart"
iconName="md-cart"
onPress={() => {
navigation.navigate("CartScreen");
}}
/>
</HeaderButtons>
),
})}
/>
<Stack.Screen
name="ProductsDetail"
component={ProductDetails}
options={({ route }) => ({
title: route.params.productTitle,
headerTitleStyle: { fontFamily: "open-sans-bold" },
})}
/>
<Stack.Screen
name="CartScreen"
component={CartScreen}
options={{
title: "Cart Items",
headerTitleStyle: { fontFamily: "open-sans-bold" },
}}
/>
<Stack.Screen
name="OrdersScreen"
component={OrdersScreen}
options={{ title: "Orders " }}
/>
</Stack.Navigator>
);
return (
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name="MainStack" component={AppStack} />
</Drawer.Navigator>
</NavigationContainer>
);
};
export default RootNavigation;
I omitted component code below as can't access drawer.
const NavigationDrawerStructure = (props)=> {
//Structure for the navigatin Drawer
const toggleDrawer = () => {
//Props to open/close the drawer
props.navigationProps.toggleDrawer();
};
return (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity onPress={()=> toggleDrawer()}>
{/*Donute Button Image */}
<Image
source={{uri: 'https://raw.githubusercontent.com/AboutReact/sampleresource/master/drawerWhite.png'}}
style={{ width: 25, height: 25, marginLeft: 5 }}
/>
</TouchableOpacity>
</View>
);
}
Here a minified version of working implementation
https://snack.expo.dev/#emmbyiringiro/69dc5b

How to call a function to main App file? React Native

I have just started learning React Native. I am trying to insert bottom menu tabs on my first app.
I am using this code on Tabs.js (this is just the export part):
export default function Tabs() {
return (
<NavigationContainer>
<MyTabs />
</NavigationContainer>
);
}
Unfortunately, I don't know how to call it to my main App file (this is just one of my attempts):
import * as React from 'react';
import { Text, View } from 'react-native';
import Tabs from './Tabs.js';
Tabs();
I've read about exporting default function, but I don't understand how to use it in my main App file. I'm sure that this is a syntax issue.
Also, I am planning to add a background colour to all tabs. Any advice?
Thank you.
UPDATE:
This is my Tabs file.
import * as React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { MaterialCommunityIcons } from '#expo/vector-icons';
const Tabs = () => {
function Feed() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text></Text>
</View>
);
}
function Profile() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text></Text>
</View>
);
}
function MainPage() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text></Text>
</View>
);
}
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator
initialRouteName="Feed"
tabBarOptions={{
activeTintColor: '#e91e63',
}}
>
<Tab.Screen
name="Feed"
component={Feed}
options={{
tabBarLabel: '',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="home" color={color} size={size} />
),
}}
/>
<Tab.Screen
name="MainPage"
component={MainPage}
options={{
tabBarLabel: '',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="pill" color={color} size={size} />
),
}}
/>
<Tab.Screen
name="Profile"
component={Profile}
options={{
tabBarLabel: '',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="format-list-text" color={color} size={size} />
),
}}
/>
</Tab.Navigator>
);
}
return (
<NavigationContainer>
<MyTabs />
</NavigationContainer>
);
}
export default Tabs
This is my main App file.
import * as React from 'react';
import { Text, View } from 'react-native';
import Tabs from './Tabs.js';
const App=()=>{
return <Tabs />
}
Make sure to export the App as default. You most probably have a file called index.js in the root folder and that is importing your App component.
Your App.js file should look like this:
import * as React from 'react';
import { Text, View } from 'react-native';
import Tabs from './Tabs.js';
export default const App=()=>{
return <Tabs />
}
And then your index.js file looks like this:
import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => App);
You don't necessarily have to export as default, because you can only have one default export. If you export App as default you import it like this: import App from './App'; and if you export without a default, you have to import like this: import {App} from './App'
And to get an advice how to add background color to the tabs, check here: How to set the background color of Tab.Navigator?
you basically call it like would call a component
btw your Tabs should export like this
const Tabs=()=>{
/...
}
export default Tabs
const App=()=>{
return <Tabs />
}

How to use react hooks on react-native with react-navigation

This is App.js using react-navigation. There are two screens on it called HomeScreen and AddScreen.
import * as React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import HomeScreen from './src/HomeScreen';
import AddScreen from './src/AddScreen';
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Add" component={AddScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
And This is home Screen. There is a 'items' in 'useState. It is gived through Add by navigation as props.
import * as React from 'react';
import PropTypes from 'prop-types';
import { View, Text, Button } from 'react-native';
function HomeScreen({ navigation, route }) {
const [items, setItems] = React.useState([]);
React.useEffect(() => {
if (route.params?.items) {
// Post updated, do something with `route.params.post`
// For example, send the post to the server
console.log('saved');
}
}, [route.params?.items]);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
title="Create post"
onPress={() => navigation.navigate('Add', { items, setItems })}
/>
<View>
{items.map((item, i) => {
return (
<View>
<Text>{item.itemName}</Text>
<Text>{item.itemPrice}</Text>
</View>
);
})}
</View>
</View>
);
}
HomeScreen.propTypes = {
navigation: PropTypes.object.isRequired,
};
export default HomeScreen;
And AddScreen receives 'items' as route.params.
And it use 'setItems' to push his own data in it.
After adding, navigation return to HomeScreen with items that is added with new item.
import * as React from 'react';
import PropTypes from 'prop-types';
import { View, Text, Button, TextInput } from 'react-native';
function AddScreen({ route, navigation }) {
const { items, setItems } = route.params;
const [itemName, setItemName] = React.useState('');
const [itemPrice, setItemPrice] = React.useState('0');
const addItem = () => {
setItems([...items, { itemName, itemPrice }]);
setItemName('');
setItemPrice('0');
};
return (
<View>
<TextInput
multiline
placeholder="What's on your mind?"
value={itemName}
onChangeText={setItemName}
/>
<TextInput
multiline
placeholder="What's on your mind?"
value={itemPrice}
onChangeText={setItemPrice}
/>
<Button
title="Done"
onPress={() => {
addItem();
// Pass params back to home screen
navigation.navigate('Home', items);
}}
/>
</View>
);
}
AddScreen.propTypes = {
navigation: PropTypes.object.isRequired,
route: PropTypes.object.isRequired,
};
export default AddScreen;
It works well on my purpose.
But I'm not sure whether this way is correct or not using react hooks to give and receive data from parent to child.
Could you modify my code ?
You should consider using React Context API https://uk.reactjs.org/docs/context.html. Its dedicated to sharing the common state (items in your case). Here is an example:
You should create a common context for items:
ItemsState.js
import React, { useState, useContext } from 'react';
const ItemsContext = React.createContext([]);
export const ItemsProvider = ({ children }) => {
return (
<ItemsContext.Provider value={useState([])}>
{children}
</ItemsContext.Provider>
);
}
export const useItems = () => useContext(ItemsContext);
Then share the context between screens with provider in App.js like this
import {ItemsProvider} from 'ItemsState';
function App() {
return (
<ItemsProvider> // share the items between both screens
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Add" component={AddScreen} />
</Stack.Navigator>
</NavigationContainer>
</ItemsProvider>
);
}
Then use items context in each screen like this AddScreen.js
import {useItems} from './ItemsState';
function AddScreen({ route, navigation }) {
const [items, setItems] = useItems(); // <- using items context as global useState
const [itemName, setItemName] = React.useState('');
const [itemPrice, setItemPrice] = React.useState('0');
const addItem = () => {
setItems([...items, { itemName, itemPrice }]);
setItemName('');
setItemPrice('0');
};
return (
<View>
<TextInput
multiline
placeholder="What's on your mind?"
value={itemName}
onChangeText={setItemName}
/>
<TextInput
multiline
placeholder="What's on your mind?"
value={itemPrice}
onChangeText={setItemPrice}
/>
<Button
title="Done"
onPress={() => {
addItem();
// Pass params back to home screen
navigation.navigate('Home', items);
}}
/>
</View>
);
}
You can also use useReducer hook and make more Redux-like. Check out this article
https://medium.com/simply/state-management-with-react-hooks-and-context-api-at-10-lines-of-code-baf6be8302c
in order to share data between components you can use Context API or Redux, passing full objects through navigation routes is an anti-pattern, you can find more information in the docs
https://reactnavigation.org/docs/params/#what-should-be-in-params

Nested Tab Bar in stack with modal screen (React Navigation v5)

I am using react-navigation v5 right now.I have Tab navigator with 3 screens 'Home', 'Discover', 'Profile'. I need to make navigation that way i could present modal screen complitely on top of tab navigator.In docs i didn't found how to do it from Tab navigator. So i deside to nest Tab navigator inside Stack navigator. And now i have tons of issues i need to resolve:
How i can show header for each tab in Tab navigator nested inside stack.
Show modal screen from view inside 'Home'.
Since i am using typescript before v5 i was using v4 with
NavigationInjectedProps. I could access fron nested component inside 'Home' with no problems, but now i having undefined props.navigation
MainNavigator.tsx
import HomeScreen from './Home/HomeScreen';
import DiscoverScreen from './Discover/DiscoverScreen';
import ProfileScreen from './profile/ProfileScreen';
import StreamsTabScreen from './Discover/tabview/tabScreens/StreamsTabScreen';
import { Image, Platform, View } from 'react-native';
import React from 'react';
import images from 'assets/images'
import DeviceInfo from 'react-native-device-info';
import VideoPlayer from '../../library/ui/videoPlayer/VideoPlayer';
import { createStackNavigator } from '#react-navigation/stack';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
export type TabNavigationProp = {
Home: undefined; //
Discover: undefined; // Should be here all undefined ????
Profile: undefined; //
}
export type StacknavigationProp = {
TabNavigator: undefined; // Same here ???
ModalPlayer: undefined; //
}
const Tab = createBottomTabNavigator();
const Stack = createStackNavigator();
const TabNavigator = () => {
return (
<Tab.Navigator>
<Tab.Screen name='Home' component={HomeScreen} />
<Tab.Screen name='Discover' component={DiscoverScreen} />
<Tab.Screen name='Profile' component={ProfileScreen} />
</Tab.Navigator>
);
};
const MainStackNavigator = () => {
return (
<Stack.Navigator mode='modal'>
<Stack.Screen name='TabNavigator' component={TabNavigator} options={{ headerShown: false }} />
<Stack.Screen name='ModalPlayer' component={VideoPlayer} />
</Stack.Navigator>
);
}
export default MainStackNavigator;
HomeScreen.tsx
import { View, Text, StyleSheet, ScrollView } from "react-native";
import React from "react";
import StreamsScreen from '../../streamsScreen/StreamsScreen';
import VideoplayerScreen from '../../videoplayer/VideoplayerScreen';
import { CompositeNavigationProp } from '#react-navigation/native';
import { BottomTabNavigationProp } from '#react-navigation/bottom-tabs';
import { StackNavigationProp } from '#react-navigation/stack';
import { TabNavigationProp, StacknavigationProp } from "../MainNavigator";
export type HomeScreenNavigationProps = CompositeNavigationProp<
BottomTabNavigationProp<TabNavigationProp, 'Home'>,
StackNavigationProp<StacknavigationProp>
>; // made props type from docs guide...
export default class HomeScreen extends React.Component<HomeScreenNavigationProps> {
render() {
console.log(this.props.navigate); //navigate is undefined...
return (
<View style={styles.container}>
<ScrollView style={styles.scrollView}>
<View style={{ paddingBottom: 24 }}>
<StreamsScreen navigate={this.props.navigation} /> //props.navigation does not exist
<View style={styles.separator} ></View>
<VideoplayerScreen />
</View>
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
scrollView: {
flex: 1,
backgroundColor: '#0C2B33',
paddingBottom: 20,
},
separator: {
height: 1,
backgroundColor: '#3D908E'
}
});
StreamsScreen.tsx
import { View, Text, StyleSheet, Image, ActivityIndicator } from 'react-native';
import MainViewItem from '../../library/ui/MainViewItem';
import { NavigationState, SceneRendererProps, TabBar, SceneMap } from 'react-native-tab-view';
import images from 'assets/images';
import { Props as IndicatorProps } from '../../library/indicator/TabBarIndicator';
import { fetchStreamsPending, fetchStreamsRefresh } from '../../redux/actions/streamActions';
import { connect } from "react-redux";
import { RootState } from "src/redux/reducers";
import numberFormatter from "../../library/utils/numberFormatter";
import palette from 'assets/palette';
import getLanguage from '../../library/utils/isoLanguages';
import {
StreamsState,
StreamsPendingState,
StreamsErrorState,
StreamsPageOffsetState,
Stream,
StreamsRefreshState
} from '../../redux/store/types';
import { TouchableOpacity } from 'react-native-gesture-handler';
import { HomeScreenNavigationProps } from '../main/Home/HomeScreen';
interface StreamsProps {
fetchStreamsPending: typeof fetchStreamsPending;
fetchStreamsRefresh: typeof fetchStreamsRefresh;
streams: StreamsState
pending: StreamsPendingState;
error: StreamsErrorState;
pageOffset: StreamsPageOffsetState;
refresh: StreamsRefreshState;
}
type State = NavigationState<{
key: string;
}>;
type Route = {
key: string;
};
class StreamsScreen extends React.Component<StreamsProps & HomeScreenNavigationProps> { // HomeScreenNavigationProps not sure what right prop type i need here ....
...
_onPressCard = () => {
this.props.navigation.navigate('ModalPlayer'); //Property 'navigation' does not exist on type ...
this.props.navigate('ModalPlayer'); //undefined here
}
...
UPADE: I fixed the problem with navigation, i didnt implement all logic for navigation with typescript...
should do something like this:
export type TabParamList = {
Home: undefined;
Discover: undefined;
Profile: undefined;
}
export type MainStackParamList = {
TabNavigator: undefined;
Stack2Nav: undefined;
ModalPlayer: undefined;
}
export type MainStackParamList2 = {
Home: undefined;
Discover: undefined;
Profile: undefined;
}
const Tab = createBottomTabNavigator<TabParamList>();
const RootStack = createStackNavigator<MainStackParamList>();
const TabNavigator = () => {
return (
<Tab.Navigator>
<Tab.Screen name='Home' component={HomeScreen} />
<Tab.Screen name='Discover' component={DiscoverScreen} />
<Tab.Screen name='Profile' component={ProfileScreen} />
</Tab.Navigator>
);
};
const MainStackNavigator = () => {
return (
<RootStack.Navigator mode='modal'>
<RootStack.Screen name='Tab' component={Tab} options={{ headerShown: false }} />
<RootStack.Screen name='ModalPlayer' component={VideoPlayer} />
</RootStack.Navigator>
);
}
in HomeScreen.tsx :
export type HomeScreenNavigationProp = CompositeNavigationProp<
BottomTabNavigationProp<TabParamList, 'Home'>,
StackNavigationProp<MainStackParamList>
>;
type Props = {
navigation: HomeScreenNavigationProp;
};
export default class HomeScreen extends React.Component<Props> {
render() {
return (
<View style={styles.container}>
<ScrollView style={styles.scrollView}>
<View style={{ paddingBottom: 24 }}>
<StreamsScreen navigation={this.props.navigation} />
<View style={styles.separator} ></View>
<VideoplayerScreen />
</View>
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
scrollView: {
flex: 1,
backgroundColor: '#0C2B33',
paddingBottom: 20,
},
separator: {
height: 1,
backgroundColor: '#3D908E'
}
});
Now what issue left is modal screen showing header even after setup mode='modal' in root stack navigator, even tho i copy pasted code from demo in docs.
Looks like the demo gif and code didn't show same behavior, i just added
{ headerShown: false } in my modal screen options:
<RootStack.Screen
name='ModalPlayer'
component={VideoPlayer}
options={{ headerShown: false }}
/>

Categories