React Native - Component Exception - javascript

I am getting an error that says Component Exception(undefined is not an object (evaluating 'this.renderScreenComponents') when running my react native. I am trying to create a drawer menu. Before I started trying to implement the menu, everything was working fine.
import { StyleSheet } from "react-native";
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
import { createDrawerNavigator } from "#react-navigation/drawer";
import ListView from "./src/screens/components/list_view";
import DetailView from "./src/screens/components/detail_view";
import ScreenA from "./src/screens/drawer/screenA.js";
import ScreenB from "./src/screens/drawer/screenB.js";
import ScreenC from "./src/screens/drawer/screenC.js";
const Stack = createStackNavigator()
const Drawer = createDrawerNavigator()
// this is the problematic part
renderScreenComponents = () => (
<Stack.Navigator>
<Stack.Screen name="Home" component={ListView} />
<Stack.Screen name="Detail" component={DetailView} />
</Stack.Navigator>
);
export default function App() {
return (
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name="Home" children={this.renderScreenComponents} />
<Drawer.Screen name="Screen A" component={ScreenA} />
<Drawer.Screen name="Screen B" component={ScreenB} />
<Drawer.Screen name="Screen C" component={ScreenC} />
</Drawer.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
I have made sure that there are no typos in any of the files, but I still am not sure what is going on. I would sincerely appreciate any help.
Thanks in advance!
P.S. This is JavaScript

Declare your function using const or function keyword.
const renderScreenComponents = () => (
<Stack.Navigator>
<Stack.Screen name="Home" component={ListView} />
<Stack.Screen name="Detail" component={DetailView} />
</Stack.Navigator>
);

Related

Navigating from children screen to parent's sibling screen in React Navigation

I have few questions about React Navigation. I want to navigate from child screen to parent's sibling component, but I couldn't find a proper way for that. My navigation in the app looks like this:
Stack (Main)
LoginPage
Desk (DrawerNavigation)
Messages
MyAccount
Here I want to navigate to MyAccount, from Messages (Desk's child screen). How can I achieve that?
I'm using #react-navigation/stack, #react-navigation/drawer to config and useNavigation to redirect screen:
import * as React from "react";
import { Button, Text, View } from "react-native";
import { NavigationContainer, useNavigation } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
import { createDrawerNavigator } from "#react-navigation/drawer";
const STYLE = {
flex: 1,
alignItems: "center",
justifyContent: "center",
width: "100%",
};
function LoginPage() {
const navigation = useNavigation();
return (
<View style={STYLE}>
<Text>LoginPage</Text>
<Button
title="Go to DrawerNav"
onPress={() => navigation.navigate("Desk")}
/>
</View>
);
}
function Messages() {
const navigation = useNavigation();
return (
<View style={STYLE}>
<Text>Messages</Text>
<Button
title="Go to MyAccount"
onPress={() => navigation.navigate("MyAccount")}
/>
</View>
);
}
function MyAccount() {
return (
<View style={STYLE}>
<Text>MyAccount</Text>
</View>
);
}
const Drawer = createDrawerNavigator();
const Desk = () => {
return (
<Drawer.Navigator initialRouteName="Messages">
<Drawer.Screen name="Messages" component={Messages} />
</Drawer.Navigator>
);
};
const Stack = createStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="LoginPage">
<Stack.Screen name="LoginPage" component={LoginPage} />
<Stack.Screen
name="Desk"
component={Desk}
options={{ headerShown: false }}
/>
<Stack.Screen name="MyAccount" component={MyAccount} />
</Stack.Navigator>
</NavigationContainer>
);
}

React native react-navigation(v6): How to set presentation options on each screen

I'm building an chat application using react native.(for study)
I wanted to apply modal presentation mode only to the Profile screen, so I passed the option value like options={{ presentation: 'modal', headerShown: true }}, but it was not applied. However, headerShown, one of the option values, was applied normally.
How can I apply different presentation modes to different screens?
For example, in the code below, I want to use the Modal presentation mode for the Profile screen and the Card presentation mode for the Chat screen.
import React from 'react';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import Profile from '../screens/profile';
import Chat from '../screens/chat';
const NativeStack = createNativeStackNavigator();
const ScreensRouter = () => (
<NativeStack.Navigator screenOptions={{ headerShown: false }}>
<NativeStack.Screen name="Profile" component={Profile} />
<NativeStack.Screen name="Chat" component={Chat} />
</NativeStack.Navigator>
);
export default ScreensRouter;
Additionally, below is the full code.
// rootRouter.js : Entry point
import React from 'react';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import ScreensRouter from './screensRouter';
import TabRouter from './tabRouter';
const NativeStack = createNativeStackNavigator();
const RootRouter = () => {
return (
<NativeStack.Navigator
screenOptions={{
headerShown: false,
presentation: 'modal',
}}
>
<NativeStack.Screen name="TabRouter" component={TabRouter} />
<NativeStack.Screen name="ScreensRouter" component={ScreensRouter} />
</NativeStack.Navigator>
);
};
export default RootRouter;
// screensRouter.js
import React from 'react';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import Profile from '../screens/profile';
import AddFriends from '../screens/addFirend';
import SearchFriend from '../screens/searchFriend';
import Chat from '../screens/chat';
import EditProfile from '../screens/editProfile';
import FaceTime from '../screens/faceTime';
import FullImage from '../screens/fullImage';
const NativeStack = createNativeStackNavigator();
const ScreensRouter = () => (
<NativeStack.Navigator screenOptions={{ headerShown: false }}>
<NativeStack.Screen
name="Profile"
component={Profile}
options={{ presentation: 'modal', headerShown: true }}
/>
<NativeStack.Screen name="AddFriend" component={AddFriends} />
<NativeStack.Screen name="SearchFriend" component={SearchFriend} />
<NativeStack.Screen name="Chat" component={Chat} />
<NativeStack.Screen name="EditProfile" component={EditProfile} />
<NativeStack.Screen name="FaceTime" component={FaceTime} />
<NativeStack.Screen name="FullImage" component={FullImage} />
</NativeStack.Navigator>
);
export default ScreensRouter;
As per documentation https://reactnavigation.org/docs/modal/, what you are most likely looking for is <Stack.Group/> for setting different behavior of screens.
Check code below:
function RootStackScreen() {
return (
<RootStack.Navigator>
<RootStack.Group>
<RootStack.Screen name="Home" component={HomeScreen} />
<RootStack.Screen name="Details" component={DetailsScreen} />
</RootStack.Group>
<RootStack.Group screenOptions={{ presentation: 'modal' }}>
<RootStack.Screen name="MyModal" component={ModalScreen} />
</RootStack.Group>
</RootStack.Navigator>
);
}

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.

Using navigation.openDrawer in Stack Navigator

I am trying to use the navigation prop inside my Stack Navigator to open the drawer when the material icon is clicked. However when I click th button I recieve the error:
Undefined is not an object (evaluating navigation.openDrawer)
I am confused as I have passed the navigation prop into the 'App' function. Where am I going wrong here?
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import {createDrawerNavigator} from '#react-navigation/drawer';
import HomeScreen from './src/screens/HomeScreen';
import SecondScreen from './src/screens/SecondScreen.js';
import {MaterialIcons} from '#expo/vector-icons';
const Drawer = createDrawerNavigator();
const Stack = createStackNavigator();
const TheDrawer = () => {
return(
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="SecondScreen" component={SecondScreen} />
</Drawer.Navigator>
);
}
const App = ({navigation}) =>{
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen
name="Home"component={TheDrawer}
options={{headerTitle:
<View>
<MaterialIcons
name='menu'
onPress={() => navigation.openDrawer()} size={28}
/>
</View>
}}
/>
<Stack.Screen name="SecondScreen" component={SecondScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
export default App;
The navigation prop only exist inside a Navigator, and different Navigators will have different navigation props (the Stack Navigator navigation will NOT have the openDrawer method, for example). I think that what you want to accomplish is this:
const App = () => {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen
name="Home"
component={HomeScreen}
options={({ navigation }) => ({
headerTitle: (
<View>
<MaterialIcons name="menu" onPress={() => navigation.openDrawer()} size={28}/>
</View>
),
})}
/>
<Drawer.Screen name="SecondScreen" component={SecondScreen} />
</Drawer.Navigator>
</NavigationContainer>
);
};
Or, if you want the menu button available on every page header:
const App = () => {
return (
<NavigationContainer>
<Drawer.Navigator
initialRouteName="Home"
screenOptions={({ navigation }) => ({
headerTitle: (
<View>
<MaterialIcons name="menu" onPress={() => navigation.openDrawer()} size={28} />
</View>
),
})}
>
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="SecondScreen" component={SecondScreen} />
</Drawer.Navigator>
</NavigationContainer>
);
};
Source: https://reactnavigation.org/docs/headers/
If you need to access more pages inside this two (Home, SecondScreen), you can create it like this:
const HomeScreen = () => {
<Stack.Navigator>
<Stack.Screen name="Home1" component={HomeScreen1} />
<Stack.Screen name="Home2" component={HomeScreen2} />
<Stack.Screen name="Home3" component={HomeScreen3} />
</Stack.Navigator>
}
Source: https://reactnavigation.org/docs/nesting-navigators

React native navigation in flatlist

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;

Categories