I'm making an aplication using router flux. Everything works fine until I encountered this problem. I don't know how can i pass a function with some parameters from the a form, to the toolbar (where the user should press the send button). Here is the where the router is defined:
export default class App extends Component {
render() {
return (
<Router>
<Scene key="root" hideNavBar={true}>
<Scene key="SplashPage" component={SplashPage} initial={true} panHandlers={null}/>
<Scene key="drawer" component={NavigationView} open={false} direction="vertical">
<Scene key="main" hideNavBar={false}>
<Scene key="MainPage" component={MainPage} search="" title={I18n.t("nautal")} mainIcon="menu" secondaryIcon={["search"]} mainAction={()=>Actions.refresh({key: 'drawer', open: value => !value })} secondaryAction={()=>Actions.SearchBoatsPage()} navBar={MyToolbar} panHandlers={null}/>
<Scene key="CheckListPage" component={CheckListPage} title={I18n.t("checklist")} navBar={MyToolbarEmpty} panHandlers={null}/>
<Scene key="MeteoPage" component={MeteoPage} title={I18n.t("meteo")} mainIcon="menu" secondaryIcon={["search","done"]} navBarSearch={true} mainAction={()=>Actions.refresh({key: 'drawer', open: value => !value })} navBar={MyToolbar} panHandlers={null}/>
<Scene key="InfoPortsPage" component={InfoPortsPage} title={I18n.t("infoPorts")} navBar={MyToolbar} mainIcon="menu" secondaryIcon={["search","done"]} mainAction={()=>Actions.refresh({key: 'drawer', open: value => !value })} navBarSearch={true} panHandlers={null}/>
<Scene key="ToolsPage" component={ToolsPage} title={I18n.t("tools")} navBar={MyToolbarEmpty} panHandlers={null}/>
<Scene key="SearchBoatsPage" component={SearchBoatsPage} title={I18n.t("searchBoats")} mainIcon="arrow-back" secondaryIcon={["done"]} mainAction={()=>Actions.pop()} secondaryAction={()=>Actions.MainPage()} navBar={MyToolbar} panHandlers={null}/>
<Scene key="CompassPage" component={CompassPage} title={I18n.t("compass")} navBar={MyToolbarEmpty} panHandlers={null}/>
<Scene key="MOBPage" component={MOBPage} title={I18n.t("manOverboard")} navBar={MyToolbarEmpty} panHandlers={null}/>
</Scene>
</Scene>
</Scene>
</Router>
)
}
}
Here is the toolbar component (with the send button):
import React, { Component } from 'react';
import {StyleSheet, View, Text, TextInput, Dimensions} from 'react-native';
import {Toolbar} from 'react-native-material-design';
import I18n from '../core/Translations';
import Icon from 'react-native-vector-icons/MaterialIcons';
import { Kohana } from 'react-native-textinput-effects';
import { Actions } from 'react-native-router-flux';
var {height, width} = Dimensions.get('window');
class MyToolbar extends Component {
constructor(props) {
super(props);
this.state = {
tabBarSearch: false,
counter: false,
secondIcon: this.props.secondaryIcon[0]
};
this.pressButton = this.pressButton.bind(this);
}
pressButton() {
if(typeof this.props.secondaryAction!="undefined"){
this.props.secondaryAction();
}
if(this.props.navBarSearch){
var icon = (!this.state.counter) ? this.props.secondaryIcon[1] : this.props.secondaryIcon[0];
this.setState({
tabBarSearch: !this.state.tabBarSearch,
secondIcon: icon,
counter: !this.state.counter
});
}
}
render() {
return (
<View style={{position: 'absolute', top: 0, flex: 1, alignSelf: 'stretch', right: 0, left: 0}}>
<Toolbar
title={(this.state.tabBarSearch) ? null : this.props.title}
icon={this.props.mainIcon}
onIconPress= {this.props.mainAction}
actions={[{
icon: this.state.secondIcon,
onPress: this.pressButton
}]}
overrides={{backgroundColor: '#015B83'}}
rightIconStyle={{
margin: 10
}}
>
<Kohana
style={{ backgroundColor: '#015B83' }}
iconClass={Icon}
iconName={'search'}
iconColor={'white'}
labelStyle={{ color: 'white', fontSize: 20}}
inputStyle={{ color: 'white', fontSize: 20, fontWeigth:'bold' }}
autoFocus={true}
placeholder={'Search'}
placeholderTextColor ={'#aaa'}
/>
</Toolbar>
</View>
)
}
}
module.exports = MyToolbar;
and here is the form( where the user imputs data to send):
import React, { Component } from 'react';
import { View, Text, StatusBar, Dimensions, ScrollView } from 'react-native';
import { Actions } from 'react-native-router-flux';
import DrawerLayout from 'react-native-drawer-layout';
import TextField from 'react-native-md-textinput';
import {Button } from 'react-native-material-design';
import NavigationView from '../Components/NavigationView';
import MyToolbarEmpty from '../Components/MyToolbarEmpty';
import MyToolbar from '../Components/MyToolbar';
import I18n from '../core/Translations';
import STYLES from '../core/Styles';
import GLOBAL from '../core/Global';
var {height, width} = Dimensions.get('window');
export default class SearchBoatsPage extends Component {
constructor(props) {
super(props);
this.state = {
country:'',
area:'',
duration:'',
startDate:''
};
this.searchData = this.searchData.bind(this);
}
searchData(){
var search = {country:this.state.country, area:this.state.area, duration:this.state.duration, startDate:this.state.startDate};
Actions.MainPage({search: search});
}
render() {
const goToPageTwo = () => Actions.CheckListPage({text: 'Hello World!'});
const openDrawer = () => Actions.refresh({key: 'drawer', open: value => !value });
return (
<View>
<StatusBar
hidden={false}
backgroundColor='#096f9c'
/>
<ScrollView>
<View style={STYLES.container}>
<View style={STYLES.subContainer}>
<TextField onChangeText={country => this.setState({country})} label={ I18n.t("country") } highlightColor={'#08AE9E'} value={this.state.country}/>
<TextField onChangeText={area => this.setState({area})} label={ I18n.t("area") } highlightColor={'#08AE9E'} value={this.state.area}/>
<TextField onChangeText={duration => this.setState({duration})} label={ I18n.t("duration") } highlightColor={'#08AE9E'} value={this.state.duration}/>
<TextField onChangeText={startDate => this.setState({startDate})} label={ I18n.t("startDate") } highlightColor={'#08AE9E'} value={this.state.startDate}/>
</View>
<View style={STYLES.bottomButton}>
<Button
onPress={this.searchData}
text={ I18n.t("search") }
theme = 'dark'
textColor = 'white'
raised={true}
overrides={{backgroundColor: '#08AE9E', rippleColor:'#39beb1'}}
/>
</View>
</View>
</ScrollView>
</View>
)
}
_setDrawer() {
this.refs['DRAWER'].openDrawer();
}
}
To summarise, i want to send parameters from the form to the toolbar, so i will be able to send the form info by pressing the button on the toolbar.
Related
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
Would anyone be able to give me help regarding React Navigation with Expo? The issue is with the drawer component where the 'Hamburger' icon isn't opening or closing the component when a user presses the icon. However, it does open/close on a default swipe gesture from React Navigation. Please see below for my code:
Router:
import React from 'react';
import { NavigationContainer, DrawerActions } from '#react-navigation/native';
import { createDrawerNavigator } from '#react-navigation/drawer';
import { IconButton } from 'react-native-paper'
import i18n from '../i18n/i18n';
//Theme
import Theme from '../theme/theme'
//Components
import Menu from '../components/Menu'
//Import Interfaces
import { RootDrawerParamList } from '../utils/typescript/type.d';
import { IProps } from '../utils/typescript/props.d';
//Import Screens
import Screen1 from '../screens/Screen1';
import Screen2 from '../screens/Screen2';
import SettingsScreen from '../screens/Settings';
const Drawer = createDrawerNavigator<RootDrawerParamList>();
export default class Router extends React.Component<IProps, any> {
constructor(props: IProps) {
super(props);
}
render() {
return (
<NavigationContainer>
<Drawer.Navigator
initialRouteName='Screen1'
drawerContent={(props: any) => <Menu {...props} />}
screenOptions={({
swipeEnabled: true
})}>
<Drawer.Screen
name="Screen1"
component={Screen1}
initialParams={{ i18n: i18n, Theme: Theme }}
options={({route, navigation} : any) => ({
headerRight: () => (<IconButton icon="cog" size={24} color={Theme.colors.text} onPress={() => navigation.navigate('Settings')} />),
route: {route},
navigation: {navigation}
})}
/>
<Drawer.Screen
name="Settings"
component={SettingsScreen}
initialParams={{ i18n: i18n, Theme: Theme }}
options={({route, navigation} : any) => ({
headerTitle: i18n.t('settings', 'Settings'),
headerLeft: () => (<IconButton icon="arrow-left" color={Theme.colors.text} size={24} onPress={() => navigation.goBack()} />),
route: {route},
navigation: {navigation}
})}
/>
<Drawer.Screen
name="Screen2"
component={Screen2}
initialParams={{ i18n: i18n, Theme: Theme }}
options={({route, navigation} : any) => ({
route: {route},
navigation: {navigation}
})}
/>
</Drawer.Navigator>
</NavigationContainer>
);
}
}
Menu
import React from 'react';
import { FlatList, StyleSheet, View } from 'react-native';
import { List, Title } from 'react-native-paper';
import { getDefaultHeaderHeight } from '#react-navigation/elements';
import { DrawerItem } from '#react-navigation/drawer';
import { useSafeAreaFrame, useSafeAreaInsets } from 'react-native-safe-area-context';
//Import Interfaces
import { IListItem } from '../utils/typescript/types.d';
import { IPropsMenu } from '../utils/typescript/props.d';
import { IStateMenu } from '../utils/typescript/state.d';
//A function is used to pass the header height, using hooks.
function withHeightHook(Component: any){
return function WrappedComponent(props: IPropsMenu) {
/*
Returns the frame of the nearest provider. This can be used as an alternative to the Dimensions module.
*/
const frame = useSafeAreaFrame();
/*
Returns the safe area insets of the nearest provider. This allows manipulating the inset values from JavaScript. Note that insets are not updated synchronously so it might cause a slight delay for example when rotating the screen.
*/
const insets = useSafeAreaInsets();
return <Component {...props} headerHeight={getDefaultHeaderHeight(frame, false, insets.top)} />
}
}
class Menu extends React.Component<IPropsMenu, IStateMenu> {
constructor(props: IPropsMenu) {
super(props);
this.state = {
menu: [
{
name: 'screen1.name',
fallbackName: 'Screen 1',
icon: 'dice-multiple-outline',
iconFocused: 'dice-multiple',
onPress: this.props.navigation.navigate.bind(this, 'screen1')
},
{
name: 'screen2.name',
fallbackName: 'Screen 2',
icon: 'drama-masks',
iconFocused: 'drama-masks',
onPress: this.props.navigation.navigate.bind(this, 'screen2')
}
]
}
}
renderItem = (item : IListItem) => {
const { i18n } = this.props.state.routes[0].params;
return (
<DrawerItem
label={ i18n.t(item.name, item.fallbackName) }
onPress={ item.onPress ? item.onPress: () => {} }
icon={ ({ focused, color, size }) => <List.Icon color={color} style={[styles.icon, {width: size, height: size }]} icon={(focused ? item.iconFocused : item.icon) || ''} /> }
/>
);
};
render() {
const { headerHeight } = this.props;
const { menu } = this.state;
const { Theme } = this.props.state.routes[0].params;
return (
<View>
<View style={{
backgroundColor: Theme.colors.primary,
height: headerHeight ?? 0,
}}>
<View style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-end',
}}>
<View style={{
flexDirection: 'row',
alignItems: 'center',
marginBottom: 5,
marginLeft: 5
}}>
<Title style={{ color: Theme.colors.text, marginLeft: 5 }}>
Title
</Title>
</View>
</View>
</View>
<FlatList
data={menu}
keyExtractor={item => item.name}
renderItem={({item}) => this.renderItem(item)}
/>
</View>
);
};
}
export default withHeightHook(Menu);
const styles = StyleSheet.create({
icon: {
alignSelf: 'center',
margin: 0,
padding: 0,
height:20
},
logo: {
width: 24,
height: 24,
marginHorizontal: 8,
alignSelf: 'center'
},
});
The solution to my issue was to encapsulate the drawer component in a native stack component. The 'Hamburger' icon works as expected, thanks for all the help and suggestions.
// Import Screens
import DrawRouter from './DrawRouter';
const Stack = createNativeStackNavigator<RootStackParamList>();
export default (): React.ReactElement => {
return (
<NavigationContainer>
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name="Main" component={DrawRouter} />
</Stack.Navigator>
</NavigationContainer>
);
};
Add the toogleDrawer() method to your onPress event on your Drawer.Navigator component:
onPress={()=> navigation.toggleDrawer()
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
I using the flatlist to display a list of data. I wish to pass the data into another pages, but i have no idea which kind of navigation I shd use.
import Routes from './src/Routes';
export default class App extends Component<Props> {
render() {
return (
<View style={styles.container}>
<StatusBar
backgroundColor="#1c313a"
arStyle="light-content"
/>
<Routes/>
</View>
);
}
}
import React, { Component } from 'react';
import {StyleSheet, View, StatusBar,Text} from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createDrawerNavigator } from '#react-navigation/drawer';
import HomeScreen from '../pages/HomeScreen'
import YourActivitiesScreen from '../pages/YourActivitiesScreen'
import YourFavouriteScreen from '../pages/YourFavouriteScreen'
const Drawer = createDrawerNavigator();
function MyDrawer() {
return (
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen
name="Home"
component={HomeScreen}
options={{ drawerLabel: 'Home' }}
/>
<Drawer.Screen
name="Your Activities"
component={YourActivitiesScreen}
options={{ drawerLabel: 'Your Activities' }}
/>
<Drawer.Screen
name="Your Favourite"
component={YourFavouriteScreen}
options={{ drawerLabel: 'Your Favourite' }}
/>
</Drawer.Navigator>
);
}
export default function SideMenu() {
return (
<NavigationContainer>
<MyDrawer />
</NavigationContainer>
);
}
import React, { Component } from 'react';
import {Router, Stack, Scene} from 'react-native-router-flux';
import Login from './pages/Login';
import Signup from './pages/Signup';
import SideMenu from './components/SideMenu'
export default class Routes extends Component {
render() {
return(
<Router>
<Stack key="root" hideNavBar>
<Scene key="login" component={Login} title="Login" initial/>
<Scene key="signup" component={Signup} title="Signup" />
<Scene key="home" component={SideMenu} title="HomeScreen" />
</Stack>
</Router>
);
}
}
import React, { Component } from 'react';
import {
StyleSheet,
View,
Text,
AsyncStorage,
TouchableOpacity,
FlatList,
Button,
} from 'react-native';
import DetailsScreen from './Details';
import { createDrawerNavigator, SafeAreaView } from 'react-navigation';
class HomeScreen extends Component{
constructor(props) {
super(props);
this.state = {
activitiesList: [],
}
};
renderItem = (item) => {
return (
<TouchableOpacity
onPress={() => {
console.log('test')
}}
>
<View style={styles.item}>
<Text style={styles.title}>{item.name}</Text>
</View>
</TouchableOpacity>
);
}
render(){
const listActivities = this.state.activitiesList
return (
<View>
<View style={styles.container}>
<Text style={styles.heading}>UPCOMING ACTIVITIES</Text>
</View>
<View>
<SafeAreaView>
<FlatList
data = {listActivities}
renderItem={({ item }) => this.renderItem(item)}
keyExtractor={item => item.id}
/>
</SafeAreaView>
</View>
</View>
)
}
}
I used the react-native-router-flux at the early part of system, which is login, signup and home. Now home display the flatlist, from the flatlist i have to make a onPress to navigate to another pages, the Actions in router-flux that i used before cannot work. Anyone have idea about it? or another better way navigate to to the details of flatlist?
First off, I'd refactor all the code to use just one kind of navigator (in this case, going for react-navigation). So, we will have your router-flux code combined with your
//Your routes screen
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
//... add missing imports
const Stack = createStackNavigator();
//this will be your old router-flux
const Root = () => {
return (
<Stack.Navigator>
<Stack.Screen name="login" component={Login} title="Login" initial/>
<Stack.Screen name="signup" component={Signup} title="Signup" />
<Stack.Screen name="home" component={SideMenu} title="HomeScreen" />
</Stack.Navigator>
)
}
const Drawer = () => {
return (
<Drawer.Screen
name="Home"
component={HomeScreen}
options={{ drawerLabel: 'Home' }}
/>
<Drawer.Screen
name="Your Activities"
component={YourActivitiesScreen}
options={{ drawerLabel: 'Your Activities' }}
/>
<Drawer.Screen
name="Your Favourite"
component={YourFavouriteScreen}
options={{ drawerLabel: 'Your Favourite' }}
/>
</Drawer.Navigator>
)
}
const AppContainer = () => {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Root" component={Root} />
<Stack.Screen name="Drawer" component={Drawer} />
//import your Details screen to use inside component
<Stack.Screen name="Details" component={Details} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default AppContainer
You will wrap your App.js component with this AppContainer. What we just did was to nest the navigations, your Home will be reached first and your drawer will be all in the same. Also, there is one missing stack in your code that is the one for the Details.
Right after here you are going to use all the actions from react-navigation. All the screens will receive a navigation props. Once you want to navigate from your Root, you will call the navigation just like props.navigation.navigate("Home").
The same will apply to navigate to your Detail screen from the FlatList.
//Your Home Screen
import React, { Component } from 'react';
import {
StyleSheet,
View,
Text,
AsyncStorage,
TouchableOpacity,
FlatList,
Button,
SafeAreaView
} from 'react-native';
class HomeScreen extends Component{
constructor(props) {
super(props);
this.state = {
activitiesList: [],
}
};
renderItem = (item) => {
return (
<TouchableOpacity
onPress={() => {
props.navigation.navigate("Details", { data: item })
console.log('test')
}}
>
<View style={styles.item}>
<Text style={styles.title}>{item.name}</Text>
</View>
</TouchableOpacity>
);
}
render(){
const listActivities = this.state.activitiesList
return (
<View>
<View style={styles.container}>
<Text style={styles.heading}>UPCOMING ACTIVITIES</Text>
</View>
<View>
<SafeAreaView>
<FlatList
data = {listActivities}
renderItem={({ item }) => this.renderItem(item)}
keyExtractor={item => item.id}
/>
</SafeAreaView>
</View>
</View>
)
}
}
Just added the navigation action to the code above. You have to access the params object in your Details Screen
//Details Screen
class DetailsScreen extends React.Component {
render() {
const { routes } = this.props;
return (
<View>
//Your component
<Text>{routes.data.name}</Text>
</View>
);
}
}
Just a side note. If you have a problem when navigating to a nested stack you can navigate this way using params
navigation.navigate(<YourParent>, {
screen: <YourDesiredScreen>,
params: { <YourObject> },
});
I hope it helps, at least as a guide. I didn't tested it, that's why I asked you to upload your code to expo.
I use react-navigation and couldn't be happier. All the navigation needed can be done with a simple:
this.props.navigation.navigate('ScreenName', {param1: 'Hello', param2: 'World'})
and then, when on the screen desired, get the param:
const { param1, param2 } = this.props.route.params;
More details here.
And, of course, if using function components it is even easier.
This example is form my 1st react-native-expo project but I hope that it will help you.
Bottom code is for two stack screens where I have PlayersTab screen and Player so main focus is to access Player with parms from PlayersTab using react-navigation
Navigation is in props object all you need is to destructor it in component const PlayersList = ({ navigation }) => {//your code}
import { View, Text } from 'react-native';
import React from 'react';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import PlayersList from '../personal_data_screen/PlayersList';
import PersonalDataScreenPlayer from'../personal_data_screen/PersonalDataScreenPlayer';
const Stack = createNativeStackNavigator();
const PersonalPlayerDataNavigator = ({ loginDataObject }) => {
return (
<Stack.Navigator>
<Stack.Screen options={{ headerShown: false }} name='PlayersTab'>
{(props) => (
<PlayersList {...props} loginDataObject={loginDataObject} />
)}
</Stack.Screen>
<Stack.Screen options={{ headerShown: false }} name='Player'>
{(props) => <PersonalDataScreenPlayer {...props} />}
</Stack.Screen>
</Stack.Navigator>
);
};
export default PersonalPlayerDataNavigator;
FlatList witch is in PlayersTab looks like this
<FlatList
data={Object.keys(friendList.data)}
renderItem={renderItem}
keyExtractor={keyExtractor}
navigation={navigation}
/>
const renderItem = ({ item }) => (
<Item
navigation={navigation}
account_id={friendList.data[item].account_id}
nickname={friendList.data[item].nickname}
/>
const Item = ({ nickname, account_id, navigation }) => (
<TouchableOpacity
onPress={() => navigation.navigate('Player', { account_id: account_id })}>
<View style={styles.itemView}>
<Text style={styles.playerNicknameText}>{nickname}</Text>
</View>
</TouchableOpacity>
And code for Player screen
import React from 'react';
import { View, Text } from 'react-native';
const PersonalDataScreenPlayer = ({ route }) => {
return (
<View
style={{
flex: 1,
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
}}>
<Text>{route.params.account_id}</Text>
</View>
);
};
export default PersonalDataScreenPlayer;
I am trying to add a button to get to my settings component (index.js) from my home component(main screen). For some reason this is not working, I have added different screens before and copied them as an example but I am not having any luck with this. I tripled checked the imports and they all seem good.
Here is what my AppNavigator.js looks like:
import React, { Component } from "react";
import { StatusBar, Platform } from "react-native";
import { connect } from "react-redux";
import { Scene, Router } from "react-native-router-flux";
import Login from "./components/common/login/";
import SignIn from "./components/common/signIn/";
import Register from "./components/common/register/";
import DriverStartupService from
"./components/driver/startupServices";
import DriverRootView from "./components/driver/rootView";
import DriverHome from "./components/driver/home";
import RideRequest from "./components/driver/rideRequest";
import PickRider from "./components/driver/pickRider";
import StartRide from "./components/driver/startRide";
import DropOff from "./components/driver/dropOff";
import RateRider from "./components/driver/rateRider";
import Settings from "./components/driver/settings";
import { statusBarColor } from "./themes/base-theme";
import { getAppConfig } from './actions/appConfig';
const RouterWithRedux = connect()(Router);
class AppNavigator extends Component {
static propTypes = {
driverJwtAccessToken: React.PropTypes.string
};
componentWillMount() {
console.log('Getting App Config');
this.props.getAppConfig();
}
render() {
return (
<RouterWithRedux>
<Scene key="root">
<Scene
key="login"
component={Login}
hideNavBar
initial={!this.props.driverJwtAccessToken ? true : false}
/>
<Scene key="signIn" component={SignIn} />
<Scene key="register" component={Register} />
<Scene key="driverRootView" component={DriverRootView}>
<Scene key="driverHome" component={DriverHome} />
<Scene key="rideRequest" component={RideRequest} />
<Scene key="pickRider" component={PickRider} />
<Scene key="startRide" component={StartRide} />
<Scene key="dropOff" component={DropOff} />
<Scene key="rateRider" component={RateRider} />
<Scene key="settings" component={Settings} />
</Scene>
<Scene
key="driverStartupService"
component={DriverStartupService}
hideNavBar
initial={this.props.driverJwtAccessToken}
/>
</Scene>
</RouterWithRedux>
);
}
}
function bindAction(dispatch) {
return {
getAppConfig: () => dispatch(getAppConfig())
};
}
const mapStateToProps = state => ({
driverJwtAccessToken: state.driver.appState.jwtAccessToken
});
export default connect(mapStateToProps, bindAction)(AppNavigator);
Here is the action on my home component (index.js):
import React, { Component } from "react";
import { connect } from "react-redux";
import {
View,
Platform,
TouchableOpacity,
Dimensions,
BackAndroid
} from "react-native";
import {
Content,
Text,
Header,
Button,
Icon,
Title,
Left,
Right,
Body,
Container
} from "native-base";
import { Actions, ActionConst } from "react-native-router-flux";
import {
changePageStatus,
currentLocationDriver
} from "../../../actions/driver/home";
import { logOutUserAsync } from "../../../actions/common/signin";
import styles from "./styles";
import commonColor from "../../../../native-base-
theme/variables/commonColor";
const { width, height } = Dimensions.get("window");
function mapStateToProps(state) {
return {
tripRequest: state.driver.tripRequest,
fname: state.driver.user.fname,
jwtAccessToken: state.driver.appState.jwtAccessToken
};
}
class DriverHome extends Component {
static propTypes = {
logOutUserAsync: React.PropTypes.func,
jwtAccessToken: React.PropTypes.string,
currentLocationDriver: React.PropTypes.func,
openDrawer: React.PropTypes.func
};
constructor(props) {
super(props);
this.state = {
flag: true
};
}
handleLogOut() {
this.props.logOutUserAsync(this.props.jwtAccessToken);
}
componentDidMount() {
BackAndroid.addEventListener("hardwareBackPress", () => {
Actions.pop();
});
}
render() {
// eslint-disable-line class-methods-use-this
return (
<Container>
<Header
androidStatusBarColor={commonColor.statusBarColorDark}
style={styles.iosHeader}
iosBarStyle="light-content"
>
<Left>
<Button transparent>
<Icon
name="ios-power"
style={styles.logoutLogo}
onPress={() => this.handleLogOut()}
/>
</Button>
</Left>
<Body>
<Title
style={
Platform.OS === "ios"
? styles.iosHeaderTitle
: styles.aHeaderTitle
}
>
Hero Home
</Title>
</Body>
<Right>
<Button transparent onPress={() => {
console.log('settings button')
Actions.settings()}}>
<Icon
name="ios-settings"
style={styles.logoutLogo}
/>
</Button>
</Right>
</Header>
<Content />
<View style={styles.detailsContainer}>
<Text style={styles.place}>
Please wait for a Patient request...
</Text>
</View>
<View
style={{
flex: 10,
flexDirection: "row",
alignItems: "flex-end",
justifyContent: "flex-end",
marginRight: 5,
marginTop: height - 150,
marginLeft: width - 40
}}
>
<TouchableOpacity
style={{ flexDirection: "row" }}
onPress={() => this.props.currentLocationDriver()}
>
<Icon name="ios-locate-outline" style={{ fontSize: 40, backgroundColor: 'transparent' }} />
</TouchableOpacity>
</View>
</Container>
);
}
}
function bindActions(dispatch) {
return {
openDrawer: () => dispatch(openDrawer()),
changePageStatus: newPage => dispatch(changePageStatus(newPage)),
logOutUserAsync: jwtAccessToken =>
dispatch(logOutUserAsync(jwtAccessToken)),
currentLocationDriver: () => dispatch(currentLocationDriver())
};
}
export default connect(mapStateToProps, bindActions)(DriverHome);
I can see the console.log message in my terminal so I know the onPress is working.. Any help would be appreciated. Been stuck for hours. I would be happy to share more of the code if needed. Thanks!