Why does this error appear? whereas in the previous version of react native it worked 0.66.4, API 29 with openjdk8. I don't know, I've tried using the previous version but a rendering error appears.
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: number.
Check the render method of Icon.
TabItem.js
import React from 'react'
import { StyleSheet, Text, TouchableOpacity } from 'react-native'
import { IconAbout, IconAboutActive, IconHome, IconHomeActive, IconNearby, IconNearbyActive} from '../../assets'
import { WARNA_UTAMA, WARNA_DISABLE } from '../../utils/constant'
const TabItem = ({ isFocused, onPress, onLongPress, label }) => {
const Icon = () => {
if (label === 'Home') return isFocused ? <IconHomeActive /> : <IconHome />
if (label === 'Nearby') return isFocused ? <IconNearbyActive /> : <IconNearby />
if (label === 'About') return isFocused ? <IconAboutActive /> : <IconAbout />
return <IconHome />
}
return (
<TouchableOpacity
onPress={onPress}
onLongPress={onLongPress}
style={styles.container}>
<Icon />
<Text style={styles.text(isFocused)}>
{label}
</Text>
</TouchableOpacity>
)
}
export default TabItem
const styles = StyleSheet.create({
container:{
alignItems: 'center',
},
text: (isFocused) => ({
fontSize: 13,
color: isFocused ? WARNA_UTAMA : WARNA_DISABLE,
})
})
BottomNavigator.js
import React from 'react'
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native'
import TabItem from '../TabItem';
const BottomNavigator = ({ state, descriptors, navigation }) => {
const focusedOptions = descriptors[state.routes[state.index].key].options;
if (focusedOptions.tabBarVisible === false) {
return null;
}
return (
<View style={ styles.container }>
{state.routes.map((route, index) => {
const { options } = descriptors[route.key];
const label =
options.tabBarLabel !== undefined
? options.tabBarLabel
: options.title !== undefined
? options.title
: route.name;
const isFocused = state.index === index;
const onPress = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name);
}
};
const onLongPress = () => {
navigation.emit({
type: 'tabLongPress',
target: route.key,
});
};
return (
<TabItem
key={index}
label={label}
isFocused={isFocused}
onPress={onPress}
onLongPress={onLongPress}
/>
);
})}
</View>
);
}
export default BottomNavigator
const styles = StyleSheet.create({
container:{
flexDirection: 'row',
backgroundColor: '#FFFF',
justifyContent: 'space-between',
paddingHorizontal: 48,
paddingVertical: 8,
borderRadius: 50,
}
})
Route.js
import React from 'react';
import {StyleSheet} from 'react-native';
import {createNativeStackNavigator} from '#react-navigation/native-stack';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
import {About, Home, Nearby, Splash} from '../pages';
import {BottomNavigator} from '../components';
const Stack = createNativeStackNavigator();
const Tab = createBottomTabNavigator();
const MainApp = () => {
return (
{
<Tab.Navigator tabBar={props => <BottomNavigator {...props} />}>
<Tab.Screen
name="Home"
component={Home}
options={{headerShown: false}}
/>
<Tab.Screen
name="Nearby"
component={Nearby}
options={{headerShown: false}}
/>
<Tab.Screen
name="About"
component={About}
options={{headerShown: false}}
/>
</Tab.Navigator>
}
);
};
const Router = () => {
return (
<Stack.Navigator initialRouteName="Splash">
<Stack.Screen
name="Splash"
component={Splash}
options={{headerShown: false}}
/>
<Stack.Screen
name="MainApp"
component={MainApp}
options={{headerShown: false}}
/>
</Stack.Navigator>
);
};
export default Router;
const styles = StyleSheet.create({});
This code, should can be rendered custom local icon correctly
Related
Since i've made the update of the expo SDK to the sdk 47 and update of all the modules, i've lost all my TV navigation. In fact the focus doesn't work anymore.
I've checked all the code, I don't see any problem. There is no problem on the debugger. I'm quite lost.
Can you help me please.
This is my App.js
import React, {useContext, useEffect} from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import {Context as AuthContext, Provider as AuthProvider} from './context/authContext';
import {Context as UserContext, Provider as UserProvider} from './context/userContext';
import {GlobalizeProvider, loadCldr, loadMessages} from 'react-native-globalize';
import { globalizeRef } from './services/Globalize';
import * as fr from './locales/fr.json';
import * as en from './locales/en.json';
import LoginScreen from "./screens/LoginScreen";
import BroadcastScreen from "./screens/BroadcastScreen";
import AnimatorListScreen from "./screens/AnimatorListScreen";
import SettingsScreen from "./screens/SettingsScreen";
import EntrantScreen from "./screens/EntrantScreen";
import SplashScreen from "./screens/SplashScreen";
loadCldr(
require('react-native-globalize/locale-data/fr'),
require('react-native-globalize/locale-data/en'),
);
loadMessages({fr, en});
const Stack = createStackNavigator();
const Animator = createStackNavigator();
const AnimatorStack = () => {
return (
<Animator.Navigator initialRouteName="List" screenOptions={{headerShown: false}}>
<Animator.Screen name="List" component={AnimatorListScreen} />
<Animator.Screen name="Broadcast" component={BroadcastScreen} options={{ headerShown: false }} />
<Animator.Screen name="Settings" component={SettingsScreen} />
</Animator.Navigator>
)
}
const Entrant = createStackNavigator();
const EntrantStack = () => {
return (
<Entrant.Navigator initialRouteName="Enter" screenOptions={{headerShown: false}}>
<Entrant.Screen name="Enter" component={EntrantScreen} options={{ headerShown: false }} />
<Entrant.Screen name="Settings" component={SettingsScreen} />
</Entrant.Navigator>
)
}
const App = () => {
const {state: authState, restoreInfos} = useContext(AuthContext);
const {state: userState, restoreLanguage} = useContext(UserContext);
useEffect(() => {
restoreInfos();
restoreLanguage();
}, []);
return (
(authState.loading || !userState.language) ?
// We haven't finished checking for the token yet
<Stack.Screen name="Splash" component={SplashScreen} /> :
<GlobalizeProvider ref={globalizeRef} locale={userState.language}>
<NavigationContainer>
<Stack.Navigator>
{(authState.token == null || authState.userType == null) ?
<Stack.Screen name="SignIn" component={LoginScreen} options={{ headerShown: false }} /> :
authState.userType === 'showman' ?
<Stack.Screen name="Showman" component={AnimatorStack} options={{ headerShown: false }} /> :
<Stack.Screen name="Entrant" component={AnimatorStack} options={{ headerShown: false }} />
}
</Stack.Navigator>
</NavigationContainer>
</GlobalizeProvider>
);
}
export default () => {
return (
<AuthProvider>
<UserProvider>
<App />
</UserProvider>
</AuthProvider>
)
}
And one of my screen :
import React, {useContext, useEffect, useRef, useState} from 'react';
import {Animated, StyleSheet, Text, TouchableOpacity, View} from "react-native";
import {Context as UserContext} from "../context/userContext";
import WebView from "react-native-webview";
import {LongPressGestureHandler, State as gestureState} from 'react-native-gesture-handler';
import {useGlobalize} from "react-native-globalize";
import {Ionicons} from '#expo/vector-icons';
import {useNavigation} from "#react-navigation/native";
import Colours from "../constants/Colours";
import Loader from "../components/Loader";
const EntrantScreen = () => {
const navigation = useNavigation();
const {formatMessage} = useGlobalize();
const {state: userState, getChosenAnimation} = useContext(UserContext);
const [reload, setReload] = useState(0);
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(true);
getChosenAnimation().finally(() => {
setLoading(false);
});
}, [reload]);
const reloadNow = () => {
setReload(reload + 1);
}
const goToSettings = () => {
navigation.navigate('Settings');
}
const opacityHandler = useRef(new Animated.Value(0)).current;
const fadeIn = () => {
// Will change fadeAnim value to 1 in 5 seconds
Animated.timing(opacityHandler, {
toValue: 1,
duration: 500,
useNativeDriver: true
}).start();
setTimeout(() => {
Animated.timing(opacityHandler, {
toValue: 0,
duration: 500,
useNativeDriver: true
}).start();
}, 3000);
};
const runFirst = "window.oncontextmenu = function(event) {\n" +
" event.preventDefault();\n" +
" event.stopPropagation();\n" +
" return false;\n" +
"};" +
"document.onselectstart = new Function (\"return false\");" +
"document.documentElement.style.property = 'user-select:none;';" +
"document.getElementsByClassName('aha-footer')[0].remove();";
return (
<View style={styles.mainView}>
{loading && <Loader />}
{ userState.chosenAnimation &&
<View style={styles.mainView}>
<LongPressGestureHandler
minDurationMs={5000}
onHandlerStateChange={({nativeEvent}) => {
if (nativeEvent.state === gestureState.ACTIVE) {
fadeIn();
}
}}>
<View style={styles.actionCaller}><></></View>
</LongPressGestureHandler>
<Animated.View style={{...styles.actionButtonHandler, opacity: (opacityHandler || 0)}}>
<TouchableOpacity onPress={() => reloadNow()}>
<Ionicons style={{color: Colours.bleu}} name="reload" size={48} />
</TouchableOpacity>
<TouchableOpacity onPress={() => goToSettings()}>
<Ionicons style={{color: Colours.bleu}} name="settings-outline" size={48} />
</TouchableOpacity>
</Animated.View>
<WebView
style={styles.container}
source={{uri: userState.chosenAnimation.entrant_link}}
injectedJavaScript={runFirst}
/>
</View>
}
{!loading && !userState.chosenAnimation &&
<View style={styles.viewNoAnim}>
<Text style={styles.textNoAnim}>{formatMessage('noChosenAnim')}</Text>
<View style={styles.viewIconsNoAnim}>
<TouchableOpacity style={styles.iconsNoAnim} onPress={() => reloadNow()}>
<Ionicons style={{color: Colours.bleu}} name="reload" size={48} />
</TouchableOpacity>
<TouchableOpacity style={styles.iconsNoAnim} onPress={() => goToSettings()}>
<Ionicons style={{color: Colours.bleu}} name="settings-outline" size={48} />
</TouchableOpacity>
</View>
</View>
}
</View>
)
}
const styles = StyleSheet.create({
mainView: {
flex: 1
},
actionCaller: {
width: 50,
height: 80,
position: 'absolute',
left: 0,
top: 0,
backgroundColor: 'transparent',
zIndex: 2,
opacity: 0.1
},
actionButtonHandler: {
width: 80,
height: '100%',
position: 'absolute',
left: 0,
top: 0,
justifyContent: 'space-evenly',
alignItems: 'center',
zIndex: 2
},
viewNoAnim: {
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
},
viewIconsNoAnim: {
flexDirection: 'row',
},
iconsNoAnim: {
margin: 10
},
textNoAnim: {
fontSize: 24
}
});
export default EntrantScreen;
Thanks a lot for your help.
I have a problem with react native navigation screen
Here is my problem picture:
enter image description here
As you can see the navigation screen is shown smaller than the simulator screen size.
Here is my related code
Navigation code:
import * as React from 'react';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
import Ionicons from 'react-native-vector-icons/Ionicons';
import {Text, Dimensions} from 'react-native';
import HomeScreen from '../screens/HomeScreen';
import AboutScreen from '../screens/AboutScreen';
import ProfileScreen from '../screens/ProfileScreen';
const fullScreenWidth = Dimensions.get('window').width;
const Stack = createStackNavigator();
function HomeStackScreen() {
return (
<Stack.Navigator>
<Stack.Screen name="HomeScreen" component={HomeScreen} />
</Stack.Navigator>
);
}
function AboutStackScreen() {
return (
<Stack.Navigator>
<Stack.Screen name="AboutScreen" component={AboutScreen} />
</Stack.Navigator>
);
}
function ProfileStackScreen() {
return (
<Stack.Navigator>
<Stack.Screen name="ProfileScreen" component={ProfileScreen} />
</Stack.Navigator>
);
}
const Tab = createBottomTabNavigator();
function Navigation(props) {
return (
<NavigationContainer>
<Tab.Navigator
screenOptions={({route}) => ({
headerTitle: () => {
return <Text>Header</Text>;
},
tabBarIcon: ({focused, color, size, padding}) => {
let iconName;
if (route.name === 'Home') {
iconName = focused ? 'home' : 'home-outline';
} else if (route.name === 'About') {
iconName = focused
? 'information-circle'
: 'information-circle-outline';
} else if (route.name === 'Profile') {
iconName = focused ? 'person' : 'person-outline';
}
return (
<Ionicons
name={iconName}
size={size}
color={color}
style={{paddingBottom: padding}}
/>
);
},
tabBarActiveTintColor: 'lightseagreen',
tabBarInactiveTintColor: 'grey',
tabBarLableStyle: {fontSize: 16},
tabBarstyle: {width: fullScreenWidth},
})}>
<Tab.Screen name="Home" component={HomeStackScreen} />
<Tab.Screen name="About" component={AboutStackScreen} />
<Tab.Screen name="Profile" component={ProfileStackScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
export default Navigation;
Screen code(each screen has same format):
import React from 'react';
import {SafeAreaView, Text, StyleSheet} from 'react-native';
const HomeScreen = props => {
return (
<SafeAreaView style={styles}>
<Text>Home Screen</Text>
</SafeAreaView>
);
};
export default HomeScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
App screen:
import 'react-native-gesture-handler';
import * as React from 'react';
import {useState, useEffect} from 'react';
import {Text, View, StyleSheet, Button, Linking} from 'react-native';
import Amplify, {Auth, Hub} from 'aws-amplify';
import awsconfig from './src/aws-exports';
import {Authenticator, withOAuth} from 'aws-amplify-react-native';
import InAppBrowser from 'react-native-inappbrowser-reborn';
import SignUp from './src/components/auth/SignUp';
import ConfirmSignUp from './src/components/auth/ConfirmSignUp';
import SignIn from './src/components/auth/SignIn';
import ForgotPassword from './src/components/auth/ForgotPassword';
import ChangePassword from './src/components/auth/ChangePassword';
import Navigation from './src/components/navigation/Navigation';
import UserContext from './src/components/userContext/UserContext';
async function urlOpener(url, redirectUrl) {
await InAppBrowser.isAvailable();
const {type, url: newUrl} = await InAppBrowser.openAuth(url, redirectUrl, {
showTitle: false,
enableUrlBarHiding: true,
enableDefaultShare: false,
ephemeralWebSession: false,
});
if (type === 'success') {
Linking.openURL(newUrl);
}
}
Amplify.configure({
...awsconfig,
Analytics: {
disabled: true,
},
oauth: {
...awsconfig.oauth,
urlOpener,
},
});
function Home(props) {
return (
<View>
<Navigation {...props} />
<Button title="Sign Out" onPress={() => Auth.signOut()} />
</View>
);
}
const AuthScreens = props => {
console.log(props.authState);
switch (props.authState) {
case 'signIn':
return <SignIn {...props} />;
case 'signUp':
return <SignUp {...props} />;
case 'forgotPassword':
return <ForgotPassword {...props} />;
case 'confirmSignUp':
return <ConfirmSignUp {...props} />;
case 'changePassword':
return <ChangePassword {...props} />;
case 'signedIn':
return <Home />;
case 'verifyContact':
return <Home />;
default:
return <></>;
}
};
const App = props => {
const [user, setUser] = useState({});
useEffect(() => {
Hub.listen('auth', ({payload: {event, data}}) => {
switch (event) {
case 'signIn':
case 'cognitoHostedUI':
getUser().then(userData => setUser(userData));
break;
case 'signOut':
setUser(null);
break;
case 'signIn_failure':
case 'cognitoHostedUI_failure':
console.log('Sign in failure', data);
break;
}
});
getUser().then(userData => setUser(userData));
}, []);
function getUser() {
return Auth.currentAuthenticatedUser()
.then(userData => userData)
.catch(() => console.log('Not signed in'));
}
const {googleSignIn, facebookSignIn} = props;
return (
<View style={styles.container}>
<Authenticator
usernameAttributes="email"
hideDefault={true}
authState="signIn">
<AuthScreens />
</Authenticator>
{!user && (
<View style={{marginBottom: 200}}>
<Text style={{textAlign: 'center'}}> - OR - </Text>
<Button title="Login with Google" onPress={googleSignIn} />
<Button title="Login with Facebook" onPress={facebookSignIn} />
</View>
)}
</View>
);
};
export default withOAuth(App);
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
How to fix this to fill up simulator screen?
I solve this problem by myself.
Actually the problem is in tabBarStyle!!!!
This is fixed code in Navigation.js:
import * as React from 'react';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
import Ionicons from 'react-native-vector-icons/Ionicons';
import {Text, Dimensions} from 'react-native';
import HomeScreen from '../screens/HomeScreen';
import AboutScreen from '../screens/AboutScreen';
import ProfileScreen from '../screens/ProfileScreen';
const fullScreenWidth = Dimensions.get('window').width;
const Stack = createStackNavigator();
function HomeStackScreen() {
return (
<Stack.Navigator>
<Stack.Screen name="HomeScreen" component={HomeScreen} />
</Stack.Navigator>
);
}
function AboutStackScreen() {
return (
<Stack.Navigator>
<Stack.Screen name="AboutScreen" component={AboutScreen} />
</Stack.Navigator>
);
}
function ProfileStackScreen() {
return (
<Stack.Navigator>
<Stack.Screen name="ProfileScreen" component={ProfileScreen} />
</Stack.Navigator>
);
}
const Tab = createBottomTabNavigator();
function Navigation(props) {
return (
<NavigationContainer>
<Tab.Navigator
screenOptions={({route}) => ({
headerTitle: () => {
return <Text>Header</Text>;
},
tabBarIcon: ({focused, color, size, padding}) => {
let iconName;
if (route.name === 'Home') {
iconName = focused ? 'home' : 'home-outline';
} else if (route.name === 'About') {
iconName = focused
? 'information-circle'
: 'information-circle-outline';
} else if (route.name === 'Profile') {
iconName = focused ? 'person' : 'person-outline';
}
return (
<Ionicons
name={iconName}
size={size}
color={color}
style={{paddingBottom: padding}}
/>
);
},
tabBarActiveTintColor: 'lightseagreen',
tabBarInactiveTintColor: 'grey',
tabBarLableStyle: {fontSize: 16},
tabBarStyle: {width: fullScreenWidth},
})}>
<Tab.Screen name="Home" component={HomeStackScreen} />
<Tab.Screen name="About" component={AboutStackScreen} />
<Tab.Screen name="Profile" component={ProfileStackScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
export default Navigation;
I am facing some weird behaviour with react navigation version 6.
When I have a headerLeft property assigned my headerTitleStyle doesn't work anymore.
So if I assign some value to headerLeft to place an icon let's say, my headerTitleStyle is not applying styles to the title, which is really weird.
home.navigator.js
import React from "react";
import { createNativeStackNavigator } from "#react-navigation/native-stack";
import { ProductsScreen } from "../screens/products.screen";
import { colors } from "../theme/colors";
import { fonts } from "../theme/fonts";
import { MenuIcon } from "../components/menu-icon.component";
import { TouchableOpacity } from "react-native";
const Stack = createNativeStackNavigator();
export const HomeNavigator = () => {
return (
<Stack.Navigator
initialRouteName="Products"
screenOptions={{
headerTitleStyle: { <<//Doesn't work when headerLeft is assigned.
fontFamily: fonts.black,
},
headerStyle: {
backgroundColor: colors.bg.secondary,
color:colors.brand.secondary,
},
headerLeft: () => (
<TouchableOpacity>
<MenuIcon height={52} width={52} weight={1.5} color={colors.brand.secondary} />
</TouchableOpacity>
),
}}
>
<Stack.Screen
options={{ title: "Marketplace", headerShadowVisible: false }}
name="Products"
component={ProductsScreen}
/>
</Stack.Navigator>
);
};
app.navigator.js:
import React from "react";
import { createMaterialBottomTabNavigator } from "#react-navigation/material-bottom-tabs";
import { Ionicons } from "#expo/vector-icons";
import { colors } from "../theme/colors";
import { fonts } from "../theme/fonts";
import { Text } from "react-native";
import { HomeNavigator } from "./home.navigator";
import { CartScreen } from "../screens/cart.screen";
import { SearchScreen } from "../screens/search.screen";
const Tab = createMaterialBottomTabNavigator();
export const AppNavigator = () => (
<Tab.Navigator
initialRouteName="Products"
shifting={true}
screenOptions={({ route }) => ({
tabBarLabel: (
<Text style={{ fontFamily: fonts.bold, textAlign: "center" }}>
{route.name}
</Text>
),
tabBarIcon: ({ focused, color }) => {
let iconName;
if (route.name === "Products") {
iconName = focused ? "home-sharp" : "home-outline";
} else if (route.name === "Search") {
iconName = focused ? "search" : "search-outline";
} else {
iconName = focused ? "cart" : "cart-outline";
}
// You can return any component that you like here!
return <Ionicons name={iconName} size={20} color={color} />;
},
})}
barStyle={{
backgroundColor: colors.bg.secondary,
fontFamily: fonts.regular,
}}
activeColor={colors.brand.secondary}
inactiveColor="gray"
>
<Tab.Screen name="Products" component={HomeNavigator} />
<Tab.Screen name="Search" component={SearchScreen} />
<Tab.Screen name="Cart" component={CartScreen} />
</Tab.Navigator>
);
Thanks in advance!
Hello everyone so i have started learning react native and i was trying to implement DrawerNavigation.
While doing so I was trying to invoke my HomeStackScreen from externl js file but it is throwing error "Nothing was returned from render."
my App.js is ---->
const HomeStack = createStackNavigator();
const DetailStack = createStackNavigator();
const Drawer = createDrawerNavigator();
const HomeStackScreen = (navigation) => {
<HomeStack.Navigator screenOptions={{
headerStyle: {
backgroundColor: '#009387'
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold'
}
}}>
<HomeStack.Screen name="Home" component={HomeScreen} />
</HomeStack.Navigator>
}
const DetailStackScreen = (navigation) => {
<DetailStack.Navigator screenOptions={{
headerStyle: {
backgroundColor: '#009387'
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold'
}
}}>
<DetailStack.Screen name="Home" component={DashboardScreen}/>
</DetailStack.Navigator>
}
const App = () => {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={HomeStackScreen} />
<Drawer.Screen name="Details" component={DetailStackScreen} />
</Drawer.Navigator>
{/* */}
</NavigationContainer>
);
};
export default App;
And this is my HomeScreen in which i was trying to make a login page. and here i have defined two text input and getting username and password from user and then i was trying to validate those credentials
and display the alert message .
import React, { Component } from 'react'
import {
View,
Text,
TouchableOpacity,
Button,
Alert
} from 'react-native';
import { TextInput } from 'react-native-gesture-handler';
import styles from './styles'
export default class Home extends React.Component {
constructor(props) {
super(props)
}
state = {
username:"",
password:""
}
validateUser(){
if(this.state.username="admin" && this.state.password=="admin")
{
Alert.alert("Access","You have login",[{
text:'okay',
}])
} else {
Alert.alert("ERROR","Incorrect Username/Password",[{
text:'okay',
}])
}
}
render() {
const { mainConatiner, heading, input, } = styles
return (
<View style={mainConatiner}>
<Text style={heading}>Login to Application</Text>
<TextInput style={input} placeholder={"User Name"} onChangeText={text=>this.setState({username:text})}/>
<TextInput style={input} secureTextEntry={true} placeholder={"Password"} onChangeText={text=>this.setState({password:text})}/>
<Button title={"Login"} onPress={()=>this.validateUser()} />
</View>
);
}
}
You should return the content from the components, same thing should be done for DetailStackScreen as well.
const HomeStackScreen = (navigation) => {
return (
<HomeStack.Navigator screenOptions={{
headerStyle: {
backgroundColor: '#009387'
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold'
}
}}>
<HomeStack.Screen name="Home" component={HomeScreen} />
</HomeStack.Navigator>
);
}
Here is my navigator. I have a bottomTab with 3 stack navigators as screens 'Home' 'Profile' 'Discover', and main root stack navigator with bottom tab navigator and few modal screens. I can not understand how to do Type checking with TypeScript right from guide in docs. Can someone explain me what am i doing wrong. For right now if i want to navigate from tab Home to tab Profile i can see only to 'Home' and all modal screens and to tabNavigator itself but not to tabs of my tabNavigator:
my code of mainNavigator:
export type TabParamList = {
Home: undefined;
Discover: undefined;
Profile: undefined;
}
export type MainStackParamList = {
TabNavigator: undefined;
ModalStreamsPlayer: { streamsQualitys: ParsedStream[], stream: Stream} | undefined;
ModalWebBrowser: { url: string, title: string } | undefined;
ModalVideoPlayer: { video: Video } | undefined;
}
export type HomeStackParamList = {
Home: undefined;
}
export type DiscoverStackParamList = {
Discover: undefined;
}
export type ProfileStackParamList = {
Profile: undefined;
}
const Tab = createBottomTabNavigator<TabParamList>();
const RootStack = createStackNavigator<MainStackParamList>();
const HomeStack = createStackNavigator<HomeStackParamList>();
const DiscoverStack = createStackNavigator<DiscoverStackParamList>();
const ProfileStack = createStackNavigator<ProfileStackParamList>();
const screenOptions = ({ route }): StackNavigationOptions => {
return {
title: route.name,
headerTitleStyle: {
fontFamily: 'ProximaNova-Semibold',
fontSize: 18,
textTransform: 'uppercase',
lineHeight: 22,
color: '#D6FFFD'
},
headerStyle: {
backgroundColor: '#133740',
elevation: 0,
shadowOpacity: 0,
borderBottomWidth: 0
},
headerTintColor: '#D6FFFD',
headerTitleAlign: 'center',
}
}
const TabHomeStack = () => {
return (
<HomeStack.Navigator>
<HomeStack.Screen
name='Home'
component={HomeScreen}
options={screenOptions}
/>
</HomeStack.Navigator>
);
};
const TabDiscoverStack = () => {
return (
<DiscoverStack.Navigator>
<DiscoverStack.Screen
name='Discover'
component={DiscoverScreen}
options={screenOptions}
/>
</DiscoverStack.Navigator>
);
}
const TabProfileStack = () => {
return (
<ProfileStack.Navigator>
<ProfileStack.Screen
name='Profile'
component={ProfileScreen}
options={screenOptions}
/>
</ProfileStack.Navigator>
)
}
const TabNavigator = () => {
return (
<Tab.Navigator
tabBarOptions={{
showLabel: false,
// activeTintColor: '#2F80ED',
// inactiveTintColor: '#999999',
style: {
backgroundColor: '#133740',
height: Platform.OS === 'ios' ? 94 : 60,
borderTopWidth: 0
}
}}>
<Tab.Screen
name='Home'
component={TabHomeStack}
options={{ tabBarIcon: ({color, focused, size}) => (
<Image
source={ focused ? images.tabBarIconHomeActive : images.tabBarIconHomeNormal }
/>
)}}
/>
<Tab.Screen
name='Discover'
component={TabDiscoverStack}
options={{ tabBarIcon: ({color, focused, size}) => (
<Image
source={ focused ? images.tabBarIconDiscoverActive : images.tabBarIconDiscoverNormal }
/>
)}}
/>
<Tab.Screen
name='Profile'
component={TabProfileStack}
options={{ tabBarIcon: ({color, focused, size}) => (
<Image
source={ focused ? images.tabBarIconProfileActive : images.tabBarIconProfileNormal }
/>
)}}
/>
</Tab.Navigator>
);
};
const RootStackNavigator = () => {
return (
<RootStack.Navigator mode='modal'>
<RootStack.Screen
name='TabNavigator'
component={TabNavigator}
options={{ headerShown: false }}
/>
<RootStack.Screen
name='ModalStreamsPlayer'
component={StreamsPlayer}
options={{ headerShown: false }}
/>
<RootStack.Screen
name='ModalWebBrowser'
component={WebScreen}
options={{ headerShown: false }}
/>
<RootStack.Screen
name='ModalVideoPlayer'
component={YoutubePlayer}
options={{ headerShown: false }}
/>
</RootStack.Navigator>
);
}
export default RootStackNavigator;
Home screen from Home tab:
type HomeScreenNavigationProp = CompositeNavigationProp<
BottomTabNavigationProp<HomeStackParamList, 'Home'>,
StackNavigationProp<MainStackParamList>
>;
type HomeScreenRouteProp = RouteProp<
HomeStackParamList, 'Home'
>;
export type HomeProps = {
navigation: HomeScreenNavigationProp;
route: HomeScreenRouteProp;
};
export default class HomeScreen extends React.Component<HomeProps> {
render() {
return (
<View style={styles.container}>
<ScrollView style={styles.scrollView}>
<View style={{ paddingBottom: 24 }}>
<StreamsScreen navigation={this.props.navigation} />
<View style={styles.separator}></View>
<NewsScreen navigation={this.props.navigation} />
<View style={styles.separator}></View>
<VideosScreen navigation={this.props.navigation} />
<View style={styles.separator}></View>
</View>
</ScrollView>
</View>
);
}
}
You can refer to this:
https://dev-yakuza.github.io/en/react-native/react-navigation-v5/
In this reference, source codes are provided too.
https://github.com/dev-yakuza/react-navigation-v5-exercise
Here are the steps of my case which is not the same as the above reference:
define a type for navigation params
Here are two screens in profile stack
e.g.
// profile stack params list
export type ProfileStackParams = {
Profile: undefined;
ProfileEdit: undefined;
};
the undefined means here that the params are not defined. You can specify your params if necessary.
define a navigation route prop
e.g.
using the ProfileStackParams, define a route params:
export type ProfileRouteProp = RouteProp<ProfileStackParams, 'Profile'>;
or you can define a navigation props:
export type ProfileNavigationProp = StackNavigationProp<ProfileStackParams, 'Profile'>;
setup profile stack of bottom tap navigator
// stack navigator
const Stack = createStackNavigator();
// bottom tab navigator, here I use material bottom tab navigator
//const Tab = createBottomTabNavigator<BottomTabParams>();
const Tab = createMaterialBottomTabNavigator<BottomTabParams>();
Then, setup profile stack and other stacks.
const TabProfileStack = (props): JSX.Element => {
console.log('TabProfileStack props', props);
return (
<Stack.Navigator mode="card" headerMode="screen">
<Stack.Screen
name="Profile"
component={Profile}
/>
<Stack.Screen name="ProfileEdit" component={ProfileEdit} />
</Stack.Navigator>
);
};
setup bottom navigator
const TabNavigator = (props) => {
return (
<Tab.Navigator
initialRouteName="Profile"
labeled={true}
>
<Tab.Screen
name="Feed"
component={TabFeedStack}
/>
<Tab.Screen
name="Profile"
component={TabProfileStack}
/>
</Tab.Navigator>
);
};
One problem of the tab navigator is that you cannot pass params to the child screen of tab navigator.
In this case, you can use React.useContext to set/get params.
Because of this, my Profile component does not take any props.
const ProfileScreen = (): JSX.Element => {
// use context instead of navigation params
const {authState} = useContext(AuthContext)!;
You need to use twice CompositeNavigationProp in your screen and NavigatorScreenParams for the nesting navigators, (https://reactnavigation.org/docs/typescript#combining-navigation-props) this seem a common pattern to use a modal, but docs lack.
in your navigator :
import { NavigatorScreenParams } from "#react-navigation/native";
/* ... */
export type TabParamList = {
Home: undefined;
Discover: undefined;
Profile: undefined;
}
export type MainStackParamList = {
TabNavigator: NavigatorScreenParams<TabParamList>;
ModalStreamsPlayer: {...};
ModalWebBrowser: {...};
ModalVideoPlayer: {...};
}
/* ... */
NB: if you use a StackNavigator for each tab, use NavigatorScreenParams for each one
and in your screen:
/* ... */
type PrimaryNavigator = StackNavigationProp<HomeStackParamList, "Home">;
type PrimaryNavigatorParent = BottomTabNavigationProp<TabParamList>;
type RootNavigatorParent = BottomTabNavigationProp<MainStackParamList>;
type PrimaryNavigatorNested = CompositeNavigationProp<PrimaryNavigator, RootNavigatorParent>;
type HomeProps = {
navigation: CompositeNavigationProp<PrimaryNavigatorNested, PrimaryNavigatorParent>;
route: HomeScreenRouteProp;
}
/* ... */