Navigate Between Screen React Native - javascript

I'm coming from ReactJS and a bit confused about how to navigate between screens in react native.
I'm using these react-navigation and react-navigation-stack versions:
"#react-navigation/native": "^5.8.10", "#react-navigation/stack": "^5.12.8"
So I have 2 screens already:
SplashScreenContainer
import React from 'react';
import {Text, View} from "react-native-reanimated";
class SplashScreenContainer extends React.PureComponent {
redirectToHome = () => {
const {navigation} = this.props;
navigation.navigate('HomeContainer');
}
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text onPress={() => this.redirectToHome}>
Splash Screen
</Text>
</View>
)
}
}
export default SplashScreenContainer;
HomeScreenContainer
import React from 'react';
import {Text, View} from "react-native-reanimated";
class HomeScreenContainer extends React.PureComponent {
render() {
return (
<View>
<Text>Home Screen</Text>
</View>
)
}
}
export default HomeScreenContainer;
and here's my app js to render the screens inside NavigationContainer:
App.js
import React from 'react';
import {SafeAreaView} from "react-native-safe-area-context";
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
const SplashScreenContainer = React.lazy(() => import('./app/containers/SplashScreenContainer'));
const HomeContainer = React.lazy(() => import('./app/containers/HomeContainer'));
const Stack = createStackNavigator();
class App extends React.PureComponent {
render() {
return (
<SafeAreaView>
<NavigationContainer>
<Stack.Navigatior>
<Stack.Screen name='SplashScreenContainer' component={() => <SplashScreenContainer {...this.props} />}/>
<Stack.Screen name='HomeContainer' component={() => <HomeContainer {...this.props} />}/>
</Stack.Navigatior>
</NavigationContainer>
</SafeAreaView>
)
}
}
export default App;
After I run with npm run ios command, the console gives me this error:
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
I don't understand what is this error about, what am I missing here? how can I navigate between the screens in react-native?
Any help will be much appreciated.
Thank You.
Regards

Well, I made it works. Here are the changes I made:
Remove SafeAreaView from App.js
Add {Suspense} in App.js because I forgot that React.lazy depends on Suspense
Use SafeAreaView in Home and SplashScreen imported from 'react-native'
App.js
import React, {Suspense} from 'react';
import {SafeAreaView, Text} from 'react-native';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
const SplashScreenContainer = React.lazy(() => import('./app/containers/SplashScreenContainer'));
const HomeContainer = React.lazy(() => import('./app/containers/HomeContainer'));
const Stack = createStackNavigator();
const Loading = () => {
return (
<SafeAreaView>
<Text>Loading</Text>
</SafeAreaView>
)
};
const Routes = () => {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName='SplashScreenContainer'>
<Stack.Screen
name='SplashScreenContainer'
component={SplashScreenContainer}
options={{ headerShown: false }}
/>
<Stack.Screen
name='HomeContainer'
component={HomeContainer}
options={{ headerShown: false }}
/>
</Stack.Navigator>
</NavigationContainer>
)
}
class App extends React.PureComponent {
render() {
return (
<Suspense fallback={<Loading/>}>
<Routes/>
</Suspense>
)
}
}
export default App;
SplashScreenContainer.js
import React from 'react';
import {Button, SafeAreaView} from 'react-native';
class SplashScreenContainer extends React.PureComponent {
constructor(props) {
super(props);
}
redirectToHome = () => {
const {navigation} = this.props;
navigation.navigate('HomeContainer');
};
render() {
return (
<SafeAreaView style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Button onPress={() => this.redirectToHome()} title='Go To Home Screen'/>
</SafeAreaView>
)
}
}
export default SplashScreenContainer;
HomeScreenContainer.js
import React from 'react';
import {Button, SafeAreaView} from 'react-native';
class HomeContainer extends React.PureComponent {
redirectToSplash = () => {
const {navigation} = this.props;
navigation.navigate('SplashScreenContainer');
};
render() {
return (
<SafeAreaView style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Button onPress={() => this.redirectToSplash()} title='Go To Splash Screen'/>
</SafeAreaView>
)
}
}
export default HomeContainer;
Everything's working now, I'm able to switch between SplashScreen and HomeScreen when button is clicked/tapped.

Related

TypeError: Cannot read property 'navigate' of undefined React Native

Here's a Stack Navigator inside a MainStack.js:
import React from 'react'
import { createStackNavigator } from '#react-navigation/stack';
import Main from './Main'
import ScannerMarker from './ScannerMarker';
const Stack = createStackNavigator();
export default function MainStack() {
return(
<Stack.Navigator initialRouteName='Main' screenOptions={{headerShown: false}}>
<Stack.Screen name='Main' component={Main} />
<Stack.Screen name='ScannerMarker' component={ScannerMarker} />
</Stack.Navigator>
);
}
And ScannerMarker.js:
import React from 'react';
import { StyleSheet, View, Text, Dimensions, Pressable } from 'react-native';
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
import Feather from 'react-native-vector-icons/Feather';
import Octicon from 'react-native-vector-icons/Octicons'
import Main from './Main';
export default function ScannerMarker({ navigation, setModalVisible }) {
return (
<View style={styles.markerContainer}>
<View style={styles.topContainer}>
<View style={styles.topBar}>
<MaterialIcon name="support-agent" size={32} color="#fffeef" backgroundColor={'none'} onPress={() => navigation.navigate(Main)} />
<Feather name="x" size={32} color="#fffeef" backgroundColor={'none'} onPress={() => navigation.goBack(Support)}/>
</View>
<Text style={styles.topText}>Point scanner to{'\n'}vending qr-code</Text>
</View>
<View style={styles.middleContainer}>
<View style={styles.leftContainer}></View>
<View style={styles.scannerSquare}></View>
<View style={styles.rightContainer}></View>
</View>
<View style={styles.bottomContainer}>
<Pressable style={styles.button} onPress={() => setModalVisible(false)}>
<Octicon name="number" size={20} color="#fffeef" style={styles.chargerIcon}/>
<Text style={styles.buttonText}> Enter vending{'\n'}number</Text>
</Pressable>
</View>
</View>
)
}
ScannerMarker is a part of a Scanner in Scanner.js:
import React from 'react';
import { StyleSheet, Linking, Dimensions} from 'react-native';
import QRCodeScanner from 'react-native-qrcode-scanner';
import { RNCamera } from 'react-native-camera';
import ScannerMarker from './ScannerMarker';
export default function Scanner({ modalVisible, setModalVisible }) {
onSuccess = e => {
Linking.openURL(e.data)
setModalVisible(!modalVisible)
};
return (
<QRCodeScanner
onRead={this.onSuccess}
flashMode={RNCamera.Constants.FlashMode.auto}
cameraStyle={styles.cameraStyle}
showMarker={true}
customMarker={
<ScannerMarker setModalVisible={setModalVisible}> </ScannerMarker>
}
/>
);
}
MainStack is rendered inside a Drawer Navigator in Drawer.js:
import React from 'react';
import { StyleSheet, View, Linking} from 'react-native';
import { createDrawerNavigator, DrawerItemList, DrawerContentScrollView, DrawerItem} from '#react-navigation/drawer';
import MaterialCommunityIcon from 'react-native-vector-icons/MaterialCommunityIcons';
const Drawer = createDrawerNavigator();
export default function MyDrawer(props) {
return (
<Drawer.Navigator
...
>
<Drawer.Screen
name='MainStack'
component={MainStack}
options={{
title: 'Charge Away',
drawerIcon: () => (<MaterialCommunityIcon name="lightning-bolt" size={45} color="#2E2A00" style={{marginEnd: -30, marginStart: -10}} />)
}}
/>
...
<Drawer.Navigator>
);
}
When i press on icons with "onPress={() => navigation.navigate(...)}" or onPress={() => navigation.goBack()} I get the following errors:
TypeError: Cannot read property 'navigate' of undefined and TypeError: Cannot read property 'goBack' of undefined
So I don't know what's the problem. navigation parametr is declared and all of the components are in the Stack Navigator.
Everything is wrapped in NavigationContainer in App.js:
import * as React from 'react';
import { NavigationContainer} from '#react-navigation/native';
import MyDrawer from './components/Drawer'
export default function App() {
return (
<NavigationContainer>
<MyDrawer />
</NavigationContainer>
);
}
I've solved the problem using useNavigation function:
import { View, Button } from 'react-native';
import { useNavigation } from '#react-navigation/native';
export default function MyComp() {
const navigation = useNavigation();
return (
<View>
<Button
title="Go to Home"
onPress={() => navigation.navigate('Home')}
/>
</View>
);
};
Another option is to pass navigation to MyComp with props:
export default function MyComp( {navigation} ) {
//...
};
<MyComp navigation={props.navigation} />
Source:
https://reactnavigation.org/docs/connecting-navigation-prop

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 can I have React Native navigation load component from another file?

I am trying to learn React Native navigation. This is my App.js, and it works fine, as expected:
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
class App extends Component {
HomeScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
render() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={this.HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
)
}
}
const Stack = createStackNavigator();
export default App;
Here I have defined HomeScreen in the App.js file itself. But what if I wanted to define it as a standalone component in another file (say HomeScreen.js), like so -
import React, { Component } from 'react';
import { View, Text } from 'react-native';
class HomeScreen extends Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
)
}
}
export default HomeScreen;
How would I import and use that HomeScreen in App.js? I have tried import HomeScreen from './components/HomeScreen' and <Stack.Screen name="Home" component={HomeScreen} /> but that gives me an error saying that it's not a component. I know this is a simple, basic question, but so far I've not been able to find an answer anywhere. Is there a different navigation library I should be using to solve this problem?
I fixed it. What I was trying to do is give the component value JSX style, like component={<HomeScreen />} but it should just be component={HomeScreen}.

ERROR: Touchable child must either be native or forward setNativeProps to a native component

I am currently doing ReactNative course from coursera and the course is 4 years old and i am facing this error: Touchable child must either be native or forward setNativeProps to a native component.
I've no idea what this is. It will be greatly helpful if someone will help me.Adding files details as well:
App.js
import React from 'react';
import Main from './components/MainComponent';
export default class App extends React.Component {
render() {
return (
<Main />
);
}
}
MainComponent.js
import React, { Component } from 'react';
import Menu from './MenuComponent';
import { DISHES } from '../shared/dishes';
import Dishdetail from './DishdetailComponent';
import { View } from 'react-native';
class Main extends Component {
constructor(props) {
super(props);
this.state = {
dishes: DISHES,
selectedDish: null,
};
}
onDishSelect(dishId) {
this.setState({selectedDish: dishId})
}
render() {
return (
<View style={{flex:1}}>
<Menu dishes={this.state.dishes} onPress={(dishId) => this.onDishSelect(dishId)} />
<Dishdetail dish={this.state.dishes.filter((dish) => dish.id === this.state.selectedDish)[0]} />
</View>
);
}
}
export default Main;
MenuComponent.js
import React from 'react';
import { View, FlatList } from 'react-native';
import { ListItem } from 'react-native-elements';
function Menu(props) {
const renderMenuItem = ({item, index}) => {
return (
<View>
<ListItem
key={index}
title={item.name}
subtitle={item.description}
hideChevron={true}
onPress={() => props.onPress(item.id)}
leftAvatar={{ source: require('./images/uthappizza.png')}}
/>
</View>
);
};
return (
<View>
<FlatList
data={props.dishes}
renderItem={renderMenuItem}
keyExtractor={item => item.id.toString()}
/>
</View>
);
}
export default Menu;
Dishdetailcomponent.js
import React from 'react';
import { Text, View } from 'react-native';
import { Card } from 'react-native-elements';
function Dishdetail(props) {
return(
<View >
<RenderDish dish={props.dish} />
</View>
);
}
function RenderDish(props) {
const dish = props.dish;
if (dish != null) {
return(
<View>
<Card
featuredTitle={dish.name}
image={require('./images/uthappizza.png')}>
<Text style={{margin: 10}}>
{dish.description}
</Text>
</Card>
</View>
);
}
else {
return(<View></View>);
}
}
export default Dishdetail;
Help will be appreciated!!
Thanks
I had same issue some days before. Quickfix for this issue.
import TouchableOpacity form 'react-native';
Add following in the MenuComponent.js
<ListItem
Component={TouchableOpacity}
key={item.id}
title={item.name}
subtitle={item.description}
hideChevron={true}
onPress={() => props.onPress(item.id)}
leftAvatar={{ source: require('./images/uthappizza.png')}}
/>
and run the program again. This will fix your problem.

React native Algolia Search undefined is not an object

import React, { Component } from "react";
import PropTypes from "prop-types";
import { View, StyleSheet, TextInput } from "react-native";
import algoliasearch from "algoliasearch/lite";
import { InstantSearch } from "react-instantsearch-native";
import {
connectSearchBox,
connectInfiniteHits,
connectHits,
connectAutoComplete,
connectStateResults,
} from "react-instantsearch/connectors";
import { FlatList } from "react-native-gesture-handler";
class SearchBox extends Component {
render() {
return (
<View style={styles.searchBoxContainer}>
<TextInput
style={styles.searchBox}
onChangeText={(query) => {
this.props.refine(query);
}}
placeholder={"Search Gangs"}
clearButtonMode={"always"}
clearButtonMode={"always"}
spellCheck={false}
autoCorrect={false}
autoCapitalize={"none"}
/>
</View>
);
}
}
const ConnectedSearchBox = connectSearchBox(SearchBox);
class InfiniteHits extends Component {
onEndReached = () => {
if (this.props.hasMore) {
this.props.refine();
}
};
render() {
return (
<FlatList
renderItem={({ item }) => (
<View>
<Text>{item.basicData.selectedStudentName}</Text>
</View>
)}
data={this.props.hits}
keyExtractor={(item) => item.objectID}
onEndReached={this.onEndReached}
ItemSeparatorComponent={() => <View style={styles.ItemSeparator} />}
/>
);
}
}
const ConnectedInfiniteHits = connectInfiniteHits(InfiniteHits);
class SearchGangsAlgolia extends Component {
constructor(props) {
super(props);
}
render() {
console.log(this.props);
return (
<View
style={{
flex: 1,
alignItems: "center",
flexDirection: "column",
paddingTop: 20,
}}
>
<InstantSearch
appId=""
apiKey=""
indexName="criminals"
>
<ConnectedSearchBox />
<ConnectedInfiniteHits />
</InstantSearch>
</View>
);
}
}
const styles = StyleSheet.create({});
export default SearchGangsAlgolia;
Here in the above code, I'm trying to fetch data from algolia, as search results but, I'm getting error
in the page as "Type error, undefined is not an object(Evaluating 'client.addAlgoliaAgent') this error is located at InstantSearch. I don't know whether which npm package to install or to import from any of npm package. But it's throwing error in instantsearch".
If anybody is still looking for the answer, the reason why you're getting this error is because you did not include the property searchClient in your InstantSearch component
install algoliasearch (npm install algoliasearch ) and import it and use it like this:
import algoliasearch from "algoliasearch/lite";
create the searchClient as follows
const searchClient = algoliasearch("appId", "apiKey");
then finally include it in your InstantSearch component like this:
<InstantSearch
appId=""
apiKey=""
indexName="criminals"
searchClient={searchClient}
>
<ConnectedSearchBox />
<ConnectedInfiniteHits />
</InstantSearch>
It worked for me

Categories