The app is for looking up information about product from an api, either by article or ean code.
User can input Article code or EAN in TextInput or scan a barcode and get the information about the product from the api.
The problem im having is i'm not able to pass the search queries from the Textinput to the queriesString in the Context Provider.
This is the error code im getting.
> ReferenceError: Can't find variable: queriesString
For what i'm able to find out the code should work, but since its my first app in react native im most likely missing something.
App
App.js
import { NavigationContainer } from "#react-navigation/native";
import { createNativeStackNavigator } from "#react-navigation/native-stack";
import HomeScreen from "./app/screens/HomeScreen";
import ScannerScreen from "./app/screens/ScannerScreen";
import { queriesContext } from "./app/global/queriesContext";
const Stack = createNativeStackNavigator();
export default function App() {
return (
<>
<queriesContext.Provider value={{ queriesString: "123456789" }}>
{console.log(queriesString + " - From App")}
<NavigationContainer>
<Stack.Navigator initialRouteName='Home' screenOptions={{ headerShown: false }}>
<Stack.Screen name='Home' component={HomeScreen} />
<Stack.Screen name='Scanner' component={ScannerScreen} />
</Stack.Navigator>
</NavigationContainer>
</queriesContext.Provider>
</>
);
}
HomeScreen
HomeScreen.js
import { StyleSheet, Text, View, Image, SafeAreaView, Platform, TextInput, Button, TouchableWithoutFeedback, Keyboard } from "react-native";
import { useNavigation } from "#react-navigation/native";
import React, { useContext, useState, useEffect } from "react";
import ProductScreen from "../global/GetData";
import { queriesContext } from "../global/queriesContext";
export default function HomeScreen() {
const [queriesString, setQueriesString] = useContext(queriesContext);
const [queries, setQueries] = useState(queriesString);
const navigation = useNavigation();
const handleSearch = () => {
setQueriesString(queries);
};
ProductScreen();
//console.log(useState.q);
return (
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<SafeAreaView style={styles.MainScreen}>
<ProductScreen />
<TextInput style={styles.TextField} editable={true} maxLength='30' numberOfLines='1' placeholder='Art no.' keyboardType='numeric' onChange={(text) => setQueries(text)} />
<Button color='red' title='Search' onPress={handleSearch} />
<View style={styles.BarcodeBox}>
<TouchableWithoutFeedback onPress={() => navigation.navigate("Scanner")}>
<Image style={styles.BarcodeImage} source={require("../assets/barcode.png")} />
</TouchableWithoutFeedback>
</View>
</SafeAreaView>
</TouchableWithoutFeedback>
);
}
const styles = StyleSheet.create({
MainScreen: {.............},
});
ScannerScreen
Not complete since i can't get to pass the value from HomeScreen to context.
ScannerScreen.js
import React, { Component, useState, useEffect } from "react";
import { Text, View, Alert, StyleSheet } from "react-native";
import { BarCodeScanner } from "expo-barcode-scanner";
export default function ScannerScreen() {
const [hasPermission, setHasPermission] = useState(null);
const [scanned, setScanned] = useState(false);
useEffect(() => {
const getBarCodeScannerPermissions = async () => {
const { status } = await BarCodeScanner.requestPermissionsAsync();
setHasPermission(status === "granted");
};
getBarCodeScannerPermissions();
}, []);
const handleBarCodeScanned = ({ type, data }) => {
setScanned(true);
Alert.alert("Strekkode", data, [{ text: "Yes", onPress: () => setScanned(false) }, { text: "No" }]);
};
if (hasPermission === null) {
return <Text>Requesting for camera permission</Text>;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<BarCodeScanner onBarCodeScanned={scanned ? undefined : handleBarCodeScanned} style={[StyleSheet.absoluteFill, styles.container]}>
<View style={styles.layerTop} />
<View style={styles.layerCenter}>
<View style={styles.layerLeft} />
<View style={styles.focused} />
<View style={styles.layerRight} />
</View>
<View style={styles.layerBottom} />
</BarCodeScanner>
);
}
const opacity = "rgba(0, 0, 0, .5)";
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: "column",
},
layerTop: {
flex: 2,
backgroundColor: opacity,
},
layerCenter: {
flex: 1,
flexDirection: "row",
},
layerLeft: {
flex: 1,
backgroundColor: opacity,
},
focused: {
flex: 10,
},
layerRight: {
flex: 1,
backgroundColor: opacity,
},
layerBottom: {
flex: 2,
backgroundColor: opacity,
},
});
GetData
GetData.js
import { StyleSheet, Text, View, Image, SafeAreaView, Platform, TextInput, Button, TouchableWithoutFeedback, Keyboard } from "react-native";
import React, { useContext, useState, useEffect } from "react";
import { queriesContext } from "./queriesContext";
export default ProductScreen = () => {
const [queriesString] = useContext(queriesContext);
const [isLoading, setLoading] = useState(true);
const [isPromotion, setPromotion] = useState(false);
const [data, setData] = useState({
results: [BEFORE API IS CALLED NOT...],
});
console.log(queriesString + " - From GetData");
useEffect(() => {
fetch(
"SERVER.........",
{
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"x-algolia-agent": "Algolia for JavaScript (4.13.1); Browser; JS Helper (3.10.0)",
"x-algolia-application-id": "***********",
"x-algolia-api-key": "************************",
},
body: JSON.stringify({
requests: [
{
indexName: "prod_products",
params: "query=" + queriesString,
},
],
}),
}
)
.then((respnse) => respnse.json())
.then((json) => setData(json), console.log(data))
.catch((error) => console.error(error))
.finally(() => setLoading(false));
}, []);
//console.log(data);
//console.log(quaryString);
return (
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<SafeAreaView style={styles.ProductScreen}>
<View style={styles.LogoBox}>
<Image source={require("../assets/Logo.png")} />
<Image
style={styles.ProductImage}
resizeMode='contain'
source={
isLoading
? require("../assets/fallback_266x266.png")
: {
uri: "https://................/" + data.results[0].hits[0].picture.product,
}
}
/>
</View>
<View>
<View>
<Text style={styles.Title}> {data.results[0].hits[0].name.no} </Text>
<Text style={styles.Desciption}>{data.results[0].hits[0].description.no}</Text>
<Text style={[styles.Text, styles.color]}>{data.results[0].hits[0].potentialPromotionsLabels[5110].text.no}</Text>
<Text style={styles.Text}> Price: {data.results[0].hits[0].code}</Text>
<Text style={styles.Text}> Article No: {data.results[0].hits[0].code}</Text>
<Text style={styles.Text}> EAN: {data.results[0].hits[0].ean}</Text>
</View>
</View>
</SafeAreaView>
</TouchableWithoutFeedback>
);
};
const styles = StyleSheet.create({
color: {................},
});
queriesContext
queriesContext.js
import { createContext } from "react";
export const queriesContext = createContext();
Error
ERROR ReferenceError: Can't find variable: queriesString
This error is located at:
in App (created by withDevTools(App))
in withDevTools(App)
in RCTView (created by View)
in View (created by AppContainer)
in RCTView (created by View)
in View (created by AppContainer)
in AppContainer
in main(RootComponent)
ERROR ReferenceError: Can't find variable: queriesString
This error is located at:
in App (created by withDevTools(App))
in withDevTools(App)
in RCTView (created by View)
in View (created by AppContainer)
in RCTView (created by View)
in View (created by AppContainer)
in AppContainer
in main(RootComponent)
If anyone could help i would greatly appreciate it
I finally got it to work.
Renamed a few things (queriesString, setQueriesString to Quary, setQuary) only to make it easier not to misspell.
I changed the brackets to curly braces in HomeScreen.js and GetData.js as suggested by Fanchen Bao.
In the HomeScreen.js from
export default function HomeScreen() {
const [ Quary, setQuary ] = useContext(queriesContext);
const [queries, setQueries] = useState("0");
To
export default function HomeScreen() {
const { Quary, setQuary } = useContext(queriesContext);
const [queries, setQueries] = useState("0");
And in GetData.js from
export default ProductScreen = () => {
const [ Quary ] = useContext(queriesContext);
to
export default ProductScreen = () => {
const { Quary } = useContext(queriesContext);
Then in the App.js i added a component and useState
export default function App() {
const [Quary, setQuary] = useState("95335");
In GetData i had also imported the context from
import { queriesContext } from "./queriesContext";
This was wrong and i changed this to the correct path
import { queriesContext } from "../global/queriesContext";
After this i still wasn't able to update the context correctly, and i found out that i should use onChangeText instead of onChange in the Textinput.
onChange resulted in the context updating, but the value was not the value in the Textinput field. insted it was returning [object Object].
LOG [object Object]
Related
I'm working on a React-Native project using expo and I'm facing an issue.
Here is my code.
This is the navSlicer
navSlice.js
import { createSlice } from "#reduxjs/toolkit";
const initialState = {
origin: null,
destination: null,
travelTimeInformation: null,
}
export const navSlice = createSlice ({
name: 'nav',
initialState,
reducers: {
setOrigin: (state, action) => {
state.origin = action.payload;
},
setDestination: (state, action) => {
state.destination = action.payload;
},
setTravelTimeInformation: (state, action) => {
state.travelTimeInformation= action.payload;
},
},
});
export const { setOrigin, setDestination, setTravelTimeInformation} = navSlice.actions;
//Selectors
export const selectOrigin = (state) => state.nav.origin;
export const selectDestination = (state) => state.nav.destination;
export const selectTravelTimeInformation = (state) => state.nav.travelTimeInformation;
export default navSlice.reducer;
HomeScreen.js
import { StyleSheet, Text, View, TextInput, KeyboardAvoidingView, Alert, DeviceEventEmitter } from 'react-native'
import React, { useEffect, useRef, useState } from 'react'
import Map from "../../components/Map"
import CustomInput from './CustomInput'
import CustomButton from './CustomButton'
const HomeScreen = () => {
const [showStart, setShowStart] = useState(false);
const showOrigin = () => {
if(showStart) {
return (
<View>
<CustomInput text="Pornire:" placeholder="Initial location"></CustomInput>
</View>
)
}
}
return (
<View style={styles.container}>
{/* <View style={styles.navbar}>
<Ionicons name='md-arrow-back-outline' onPress={handleBackButton} style={styles.arrow} size={32} ></Ionicons>
<Ionicons name='notifications-outline' style={styles.icons} size={32} ></Ionicons>
<Ionicons name='settings-outline' size={32} ></Ionicons>
</View> */}
<View style={{padding: 15, flex: 0}}>
{showOrigin()}
<CustomInput text="Destinatie" placeholder="Destination"></CustomInput>
<CustomButton text="Cauta" onPress={() => setShowStart(true)}></CustomButton>
</View>
<Map styles={styles.map} />
</View>
)
}
This is my Custom Input file for Homescreen that also contains my GooglePlacesAutocomplete component which comunicates with reducer
CustomInput.js
import { StyleSheet, Text, View, TextInput } from 'react-native'
import React, { useState } from 'react'
import { GooglePlacesAutocomplete } from 'react-native-google-places-autocomplete';
import { GOOGLE_API_KEY } from '#env'
import { useDispatch } from 'react-redux';
import { setDestination, setOrigin } from '../../components/navSlice';
const CustomInput = ({text, placeholder}) => {
const dispatch = useDispatch();
return (
<View>
<Text style={styles.text}>{text}</Text>
<GooglePlacesAutocomplete
styles={{textInput: styles.inputGoogle, container: {flex: 0}}}
placeholder={placeholder}
fetchDetails={true}
enablePoweredByContainer={false}
minLength={2}
onPress={(data, details = null) => {
console.log(data)
console.log(details)
dispatch(setOrigin({
location: details.geometry.location,
description: data.description,
}));
dispatch(setDestination(null));
}}
query={{
key: GOOGLE_API_KEY,
language: 'en',
}}
nearbyPlacesAPI="GooglePlacesSearch"
debounce={400}
/>
</View>
)
}
export default CustomInput
The problem looks like it is coming from Map.js where is my MapView created
import { Dimensions, StyleSheet, Text, View } from 'react-native'
import React from 'react'
import MapView, { Marker, PROVIDER_GOOGLE } from 'react-native-maps'
import { useSelector } from 'react-redux'
import { selectOrigin } from './navSlice'
const Map = () => {
const origin = useSelector(selectOrigin);
return (
<MapView
style={styles.map}
provider={PROVIDER_GOOGLE}
initialRegion={{
latitude: origin.location.lat,
longitude: origin.location.lng,
latitudeDelta: 0.005,
longitudeDelta: 0.005,
}}
/>
)
}
The error is the following:
ERROR TypeError: null is not an object (evaluating 'origin.location')
This error is located at:
in Map (created by HomeScreen)
in RCTView (created by View)
in View (created by HomeScreen)
in HomeScreen (created by SceneView)
in StaticContainer
in EnsureSingleNavigator (created by SceneView)
Well, I made a presentation onboarding screen, as soon as the user opens the app, the screen is shown, but I want this to be saved using AsyncStorage, if I close and open the app, the onboarding screen is not shown, but the screen of login.
I did all the code but nothing happens and the screen is displayed every time I close and open the app, I don't know what I'm doing wrong, code below.
App.js
import React, { useEffect, useState } from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import {AuthProvider} from './src/providers/Auth';
import AsyncStorage from '#react-native-async-storage/async-storage';
import { OnBoarding } from './src/screen/OnBoarding';
import { SignIn } from './src/screen/SignIn';
import { HomeScreen } from './src/screen/HomeScreen';
import { ActivityIndicator } from 'react-native';
const Stack = createNativeStackNavigator();
const Loading = () => {
return (
<View>
<ActivityIndicator size="large" />
</View>
);
}
export function App(){
const [loading, setLoading] = useState(true);
const [viewedOnboarding, setViewedOnboarding] = useState(false);
useEffect(() => {
checkOnBoarding();
}, [])
const checkOnBoarding = async () => {
try{
const value = await AsyncStorage.getItem('#viewedOnboarding');
if(value !== null){
setViewedOnboarding(true);
}
console.log(value);
}catch(err) {
console.log('Error #checkOnboarding: ', err);
}finally {
setLoading(false)
}
}
return (
<AuthProvider>
<NavigationContainer>
<Stack.Navigator
initialRouteName={loading ? <Loading /> : viewedOnboarding ? <HomeScreen /> : <OnBoarding />}
screenOptions={
{headerShown: false}
}
>
<Stack.Screen
name="SignIn"
component={SignIn}
/>
</Stack.Navigator>
</NavigationContainer>
</AuthProvider>
);
}
Onboarding.js
import React, { useEffect, useState } from 'react';
import {Text, View, StyleSheet, Image, TouchableOpacity, Button} from 'react-native';
import AppIntroSlider from 'react-native-app-intro-slider';
import Icon from 'react-native-vector-icons/FontAwesome';
import AsyncStorage from '#react-native-async-storage/async-storage';
const slides = [
{
key: 1,
title: 'Only Books Can Help You',
text: 'Books can help you to increase your knowledge and become more successfully.',
image: require('../../assets/imagem1.png'),
},
{
key: 2,
title: 'Learn Smartly',
text: 'It’s 2022 and it’s time to learn every quickly and smartly. All books are storage in cloud and you can access all of them from your laptop or PC.',
image: require('../../assets/imagem2.png'),
},
{
key: 3,
title: 'Learn Smartly',
text: 'It’s 2022 and it’s time to learn every quickly and smartly. All books are storage in cloud and you can access all of them from your laptop or PC.',
image: require('../../assets/imagem2.png'),
},
];
export function OnBoarding(){
function renderItem({item}){
return (
<View style={styles.container}>
<Image style={styles.image} source={item.image} />
<Text style={styles.title}>{item.title}</Text>
<Text style={styles.content}>{item.text}</Text>
</View>
);
}
function _renderPrevButton() {
return (
<View style={styles.buttonCircle}>
<Icon
name="angle-left"
color="#000"
size={40}
/>
</View>
);
};
function _renderNextButton() {
return (
<View style={styles.buttonCircle}>
<Icon
name="angle-right"
color="#000"
size={40}
/>
</View>
);
};
const onPressFinish = async () => {
try{
await AsyncStorage.setItem('#viewedOnboarding', 'true')
navigation.navigate('SignIn');
}catch(err) {
console.log("Error #setitem ", err);
}
};
const renderDoneButton = () => {
return (
<TouchableOpacity onPress={onPressFinish}>
<Text style={{color: "#000"}}>Done</Text>
</TouchableOpacity>
);
};
return (
<AppIntroSlider
data={slides}
renderItem={renderItem}
keyExtractor={item => item.key}
renderPrevButton={_renderPrevButton}
renderNextButton={_renderNextButton}
renderDoneButton={renderDoneButton}
showPrevButton
showDoneButton
dotStyle={{backgroundColor: '#9D9D9D'}}
activeDotStyle={{backgroundColor: '#DE7773'}}
/>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: "#fff"
},
title: {
color: "#292B38",
fontSize: 24,
fontWeight: 'bold',
marginTop: 50
},
content: {
color: "#4D506C",
textAlign: 'center',
padding: 25,
lineHeight: 18
},
image: {
width: 300,
height: 300,
},
button: {
color: "#000",
backgroundColor: "transparent"
}
})
Probably because of the async nature of AsyncStore when you open your app first you init viewedOnboarding with false, then start reading storage and then you check is onboarding done or not. And of course because storage is async first time you check in Navigation condition you always get
I have modified your checkOnBoarding function.
Here is the code:
const checkOnBoarding = () => {
try{
AsyncStorage.getItem('#viewedOnboarding').then(value => {
if(value !== null){
setViewedOnboarding(true);
}
console.log(value);
})
}catch(err) {
console.log('Error #checkOnboarding: ', err);
}finally {
setLoading(false)
}
}
I am new in React Native. I try to create a simple searching food restaurant with Yelp. Unfortunately, I get an error:
"searchApi is not a function. (in 'searchApi(term)', 'searchApi' is
"")
Below my code.
useResults.js
import React, { useEffect, useState } from 'react';
import yelp from '../api/yelp';
export default () => {
const [result, setResult] = useState([]);
const [errorMessage, setErrorMessage] = useState('');
const searchApi = async (searchTerm) => {
console.log("hi there");
try {
const response = await yelp.get('/search', {
params: {
limit: 50,
term: searchTerm,
location: 'san jose'
}
});
setErrorMessage(null);
setResult(response.data.businesses);
} catch (err) {
setErrorMessage('Something Went Wrong');
}
};
/*
useEffect(() => {}); //Run the arrow function everytime the component is rendered
useEffect(() => {}, []); // Run the arrow function only when the component is first rendered
useEffect(() => {}, [value]); // Run the arrow function only when the component is first rendered, and when the value is changes
*/
useEffect(() => {
searchApi('pasta');
}, []);
return [searchApi, result, errorMessage];
};
SearchScreen.js
import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import ResultList from '../components/ResultList';
import SearchBar from '../components/SearchBar';
import useResults from '../hooks/useResults';
const SearchScreen = () => {
const [term, setTerm] = useState('');
const [searchApi, result, errorMessage] = useResults();
console.log(result);
return (
<View>
<SearchBar
term={term}
onTermChange={setTerm}
onTermSubmit={() => searchApi(term)}
/>
<View>{errorMessage ? <Text>{errorMessage}</Text> : null}</View>
<Text>We have found {result.length} results</Text>
<ResultList title="Cost Effective" />
<ResultList title="Bit Pricier" />
<ResultList title="Big Spender"/>
</View>
);
};
const styles = StyleSheet.create({
});
export default SearchScreen;
edit :
SearchBar.js
import React from 'react';
import { View, Text, StyleSheet, TextInput } from 'react-native';
import { Feather } from '#expo/vector-icons';
const SearchBar = ({ term, onTermChange, onTermSubmit }) => {
return (
<View style={styles.backgroundStyle}>
<Feather style={styles.iconStyle} name="search" size={30} color="black" />
<TextInput style={styles.inputStyle}
autoCapitalize="none"
autoCorrect={false}
placeholder="Search"
value={term}
onChangeText={onTermChange}
onEndEditing={onTermSubmit}
/>
</View>
)
};
const styles = StyleSheet.create({
backgroundStyle: {
marginTop: 10,
backgroundColor: '#F0EEEE',
height: 50,
borderRadius: 5,
marginHorizontal: 15,
flexDirection: 'row'
},
inputStyle: {
flex: 1,
fontSize: 18,
marginHorizontal: 10
},
iconStyle: {
fontSize: 35,
alignSelf: 'center'
}
});
export default SearchBar;
When I type in search bar and hit done button, I got the error above.
Seems in useResults.js file this: return [searchApi, result, errorMessage]; does not properly return the function. But the result and errorMessage return successfully.
And in this file: SearchScreen.js the error line is shown in here: onTermSubmit={() => searchApi(term)}.
How to fix this?
Try adding a callback to onChangeText.
<TextInput style={styles.inputStyle}
autoCapitalize="none"
autoCorrect={false}
placeholder="Search"
value={term}
onChangeText={() => onTermChange()} // Add fat arrow function here
onEndEditing={onTermSubmit}
/>
I am using react-navigation 5 in my mobile app and I am stuck in implementing a log-off feature.
The scenario is I have a stack navigator and a bottom tab navigator in my app. The app starts with the stack navigator (Login feature and Reset Password Feature) and on login goes to the dashboard Page which is from the bottom tab navigator. Now on the Dashboard page, I am implementing a logout feature which when clicked should take me to the login page (part of stack navigator), and no matter what I try it keeps giving me errors like these
The action 'RESET' with payload {"index":0,"routes":[{"name":"AuthNavigator"}]} was not handled by any navigator.
Here are my code snippets right from start
Component Called from App.js
import React, { useState, useEffect, useContext } from "react";
import { ActivityIndicator } from "react-native";
import AsyncStorage from '#react-native-async-storage/async-storage';
import { Center } from "../../components/Center";
import { AuthContext } from "../authentication/AuthProvider";
import { NavigationContainer } from "#react-navigation/native";
import { AuthNavigator } from "./AuthNavigator";
import { MainTabNavigator } from "./MainTabNavigator";
export default function App() {
const { user, login } = useContext(AuthContext);
const [loading, setLoading] = useState(true);
useEffect(() => {
// check if the user is logged in or not
//AsyncStorage.removeItem("user") //- uncomment this and refresh emulator to start from login screen
AsyncStorage.getItem("user")
.then(userString => {
if (userString) {
login();
}
setLoading(false);
})
.catch(err => {
console.log(err);
});
}, []);
if (loading) {
return (
<Center>
<ActivityIndicator size="large" />
</Center>
);
}
return (
<NavigationContainer>
{user ? <MainTabNavigator /> : <AuthNavigator />}
</NavigationContainer>
);
}
AuthNavigator.js
import React from "react";
import { createStackNavigator } from '#react-navigation/stack';
import Login from '../authentication/Login';
import ResetPassword from '../authentication/ResetPassword';
import { MainTabNavigator } from "./MainTabNavigator";
const Stack = createStackNavigator();
export const AuthNavigator = () => {
return (
<Stack.Navigator initialRouteName="Login">
<Stack.Screen name="Login" component={Login} />
<Stack.Screen name="ResetPassword" options={{headerTitle: "Reset Password"}} component={ResetPassword} />
</Stack.Navigator>
);
}
MainTabNavigator.js
import * as React from 'react';
import { Text, View, Image, StyleSheet, Platform } from 'react-native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import DashboardView from '../dashboard/DashboardView';
import Search from '../searchLoan/Search';
import { colors } from '../../styles';
const iconHome = require('../../../assets/images/tabbar/home.png');
const iconGrids = require('../../../assets/images/tabbar/grids.png');
const searchIcon = require('../../../assets/images/pages/search_24px.png');
const Tab = createBottomTabNavigator();
const tabData = [
{
name: 'Dashboard',
component: DashboardView,
icon: iconHome,
},
{
name: 'Search',
component: Search,
icon: searchIcon,
},
];
export const MainTabNavigator = () => {
return (
<Tab.Navigator tabBarOptions={{ style: { height: Platform.OS === 'ios' ? 90 : 50 } }}>
{tabData.map((item, idx) => (
<Tab.Screen
key={`tab_item${idx + 1}`}
name={item.name}
component={item.component}
options={{
tabBarIcon: ({ focused }) => (
<View style={styles.tabBarItemContainer}>
<Image
resizeMode="contain"
source={item.icon}
style={[styles.tabBarIcon, focused && styles.tabBarIconFocused]}
/>
</View>
),
tabBarLabel: ({ focused }) => <Text style={{ fontSize: 12, color: focused ? colors.primary : colors.gray }}>{item.name}</Text>,
title: item.name,
}}
/>
))}
</Tab.Navigator>
);
};
const styles = StyleSheet.create({
tabBarItemContainer: {
alignItems: 'center',
justifyContent: 'center',
borderBottomWidth: 2,
borderBottomColor: colors.white,
paddingHorizontal: 10,
bottom: Platform.OS === 'ios' ? -5 : 0,
},
tabBarIcon: {
width: 23,
height: 23,
},
tabBarIconFocused: {
tintColor: colors.primary,
},
});
DashboardView.js
import React , {useContext }from 'react';
import { StyleSheet, View, TouchableOpacity, Text } from 'react-native';
import {Header} from 'react-native-elements';
import AntIcon from "react-native-vector-icons/AntDesign";
import { colors, fonts } from '../../styles';
import AmountDetails from './AmountDetails';
import DashboardFields from './DashboardFields';
import { AuthContext } from "../authentication/AuthProvider";
import { CommonActions } from "#react-navigation/native";
export default function DashboardView(props) {
const appLogOut = () => {
const { logout } = useContext(AuthContext);
console.log('props', props)
if(logout){
// console.log("Navigation Object", navigation)
props.navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [{ name: "AuthNavigator" }],
}));
}
}
return (
<View style={styles.container}>
<Header containerStyle = {{backgroundColor: colors.primary}}
centerComponent={{ text: 'Dashboard', style: { color: colors.white, backgroundColor: colors.primary } }}
rightComponent = <TouchableOpacity onPress={appLogOut()}><AntIcon name="logout" color="white" size={25}/></TouchableOpacity>
/>
<View style={styles.container}>
<View>
<AmountDetails />
</View>
<View style={styles.dashboardFields}>
<DashboardFields />
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.gray,
},
dashboardFields: {
marginTop: 20,
},
});
You should try calling the login screen directly, not the whole stack.
CommonActions.reset({
index: 0,
routes: [{ name: "Login" }],
}));
As the other answer said, you have incorrect route name (AuthNavigator).
However, you're conditionally defining screens based on if the user is logged in. You don't need to do anything extra when logging out. Conditionally defining screens means React Navigation can automatically handle which screen to show when the conditional changes.
So you need to remove the code which does reset.
From the docs:
It's important to note that when using such a setup, you don't need to manually navigate to the Home screen by calling navigation.navigate('Home') or any other method. React Navigation will automatically navigate to the correct screen when isSigned in changes - Home screen when isSignedIn becomes true, and to SignIn screen when isSignedIn becomes false. You'll get an error if you attempt to navigate manually.
More details: https://reactnavigation.org/docs/auth-flow/
I'm making an app in react-native and I would like to navigate to different page by clicking on a button using stack navigation:
Here is my code :
app.js
import React from 'react';
import { AppRegistry } from 'react-native';
import { StackNavigator } from 'react-navigation';
import Home from './Screens/Home';
import VideoListItems from './Screens/VideoListItems';
import TrackPlayer from './Screens/TrackPlayer';
const reactNavigationSample = props => {
return <VideoListItems navigation={props.navigation} />;
};
reactNavigationSample.navigationOptions = {
title: "VideoListItems"
};
const AppNavigator = StackNavigator({
Home: { screen: Home, navigationOptions: { header: null }},
VideoListItems: { screen: VideoListItems, navigationOptions: { header: null }},
TrackPlayer: { screen: TrackPlayer, navigationOptions: { header: null }},
}
);
export default class App extends React.Component {
render() {
return (
<AppNavigator />
);
}
}
VideoListItems where the button to navigate is :
import {StackNavigator} from 'react-navigation';
const VideoListItems = ({ video, props }) => {
const { navigate } = props.navigation;
const {
cardStyle,
imageStyle,
contentStyle,
titleStyle,
channelTitleStyle,
descriptionStyle
} = styles;
const {
title,
channelTitle,
description,
thumbnails: { medium: { url } }
} = video.snippet;
const videoId = video.id.videoId;
return(
<View>
<Card title={null} containerStyle={cardStyle}>
<Image
style={imageStyle}
source= {{ uri: url}}
/>
<View style={contentStyle}>
<Text style={titleStyle}>
{title}
</Text>
<Text style={channelTitleStyle}>
{channelTitle}
</Text>
<Text style={descriptionStyle}>
{description}
</Text>
<Button
raised
title="Save And Play"
icon={{ name: 'play-arrow' }}
containerViewStyle={{ marginTop: 10 }}
backgroundColor="#E62117"
onPress={() => {
navigate('TrackPlayer')
}}
/>
</View>
</Card>
</View>
);
};
export default VideoListItems;
But I'm getting this error :
TypeError: undefined is not an object (evaluating 'props.navigation')
I don't know how to pass the props navigation and make it able to navigate when clicking on the button, I don't know where is my error, any ideas ?
[EDIT]
My new VideoItemList :
const VideoListItems = props => {
const {
cardStyle,
imageStyle,
contentStyle,
titleStyle,
channelTitleStyle,
descriptionStyle
} = styles;
const {
title,
channelTitle,
description,
thumbnails: { medium: { url } }
} = props.video.snippet;
const videoId = props.video.id.videoId;
const { navigate } = props.navigation;
return(
<View>
<Card title={null} containerStyle={cardStyle}>
<Image
style={imageStyle}
source= {{ uri: url}}
/>
<View style={contentStyle}>
<Text style={titleStyle}>
{title}
</Text>
<Text style={channelTitleStyle}>
{channelTitle}
</Text>
<Text style={descriptionStyle}>
{description}
</Text>
<Button
raised
title="Save And Play"
icon={{ name: 'play-arrow' }}
containerViewStyle={{ marginTop: 10 }}
backgroundColor="#E62117"
onPress={() => {
navigate.navigate('TrackPlayer')
}}
/>
</View>
</Card>
</View>
);
};
This is the file where I display all my components :
import React, { Component } from 'react';
import { View } from 'react-native';
import YTSearch from 'youtube-api-search';
import AppHeader from './AppHeader';
import SearchBar from './SearchBar';
import VideoList from './VideoList';
const API_KEY = 'ApiKey';
export default class Home extends Component {
state = {
loading: false,
videos: []
}
componentWillMount(){
this.searchYT('');
}
onPressSearch = term => {
this.searchYT(term);
}
searchYT = term => {
this.setState({ loading: true });
YTSearch({key: API_KEY, term }, videos => {
console.log(videos);
this.setState({
loading: false,
videos
});
});
}
render() {
const { loading, videos } = this.state;
return (
<View style={{ flex: 1, backgroundColor: '#ddd' }}>
<AppHeader headerText="Project Master Sound Control" />
<SearchBar
loading={loading}
onPressSearch={this.onPressSearch} />
<VideoList videos={videos} />
</View>
);
}
}
And my VideoList where I use VideoListItems :
import React from 'react';
import { ScrollView, View } from 'react-native';
import VideoListItems from './VideoListItems';
const VideoList = ({ videos }) => {
const videoItems = videos.map(video =>(
<VideoListItems
key={video.etag}
video={video}
/>
));
return(
<ScrollView>
<View style={styles.containerStyle}>
{videoItems}
</View>
</ScrollView>
);
};
const styles = {
containerStyle: {
marginBottom: 10,
marginLeft: 10,
marginRight: 10
}
}
export default VideoList;
That's because you try to extract navigation from a prop named props (that doesn't exist), you have many ways to solve this problem :
Use the rest operator to group all props except video inside a props variable
const VideoListItems = ({ video, ...props }) => {
Don't destructure you props object
const VideoListItems = props => {
// don't forget to refactor this line
const videoId = props.video.id.videoId;
Extract navigation from props
const VideoListItems = ({ video, navigation }) => {
const { navigate } = navigation;