i'am fairly new to react native and i'm doing a social media clone. I've got my navigator and the login via a database done , but i was wondering if there was a way to link a page/screen to another one by pressing a button .
Here is my code for the home screen after logging in :
import React, {Component} from 'react';
import {View, Text, FlatList} from 'react-native';
import AsyncStorage from '#react-native-async-storage/async-storage';
class HomeScreen extends Component {
constructor(props){
super(props);
this.state = {
isLoading: true,
listData: []
}
}
componentDidMount() {
this.unsubscribe = this.props.navigation.addListener('focus', () => {
this.checkLoggedIn();
});
this.getData();
}
componentWillUnmount() {
this.unsubscribe();
}
getData = async () => {
const value = await AsyncStorage.getItem('#session_token');
return fetch("http://localhost:3333/api/1.0.0/search", {
'headers': {
'X-Authorization': value
}
})
.then((response) => {
if(response.status === 200){
return response.json()
}else if(response.status === 401){
this.props.navigation.navigate("Login");
}else{
throw 'Something went wrong';
}
})
.then((responseJson) => {
this.setState({
isLoading: false,
listData: responseJson
})
})
.catch((error) => {
console.log(error);
})
}
checkLoggedIn = async () => {
const value = await AsyncStorage.getItem('#session_token');
if (value == null) {
this.props.navigation.navigate('Login');
}
};
render() {
if (this.state.isLoading){
return (
<View
style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
}}>
<Text>Loading..</Text>
</View>
);
}else{
return (
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}}>
<Text>Welcome to The app </Text>
</View>
);
}
}
}
export default HomeScreen;
Now ideally i would want a button in my else statement which could lead me to another screen (eg main screen of the app ) after logging in .
App.js :
import 'react-native-gesture-handler';
import React, { Component } from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createDrawerNavigator } from '#react-navigation/drawer';
import HomeScreen from './screens/home';
import LoginScreen from './screens/login';
import SignupScreen from './screens/signup';
import LogoutScreen from './screens/logout';
const Drawer = createDrawerNavigator();
class App extends Component{
render(){
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Login" component={LoginScreen} />
<Drawer.Screen name="Signup" component={SignupScreen} />
<Drawer.Screen name="Logout" component={LogoutScreen} />
</Drawer.Navigator>
</NavigationContainer>
);
}
}
export default App;
If you're new to react native, I'd suggest that you give functional components and hooks a try, this is how your code would look like as a functional component after some clean up
(The answer is included in component)
import React, { Component, useEffect, useState } from "react";
import { View, Text, FlatList, Button } from "react-native";
import AsyncStorage from "#react-native-async-storage/async-storage";
const HomeScreen = (props) => {
const [isLoading, setIsLoading] = useState(true);
const [listData, setListData] = useState([]);
useEffect(() => {
const subscription = props.navigation.addListener("focus", () => {
checkLoggedIn();
});
getData();
return subscription.remove(); //similar to component unmount, syntax might be different based on your version
}, []);
const getData = async () => {
setIsLoading(true)
const value = await AsyncStorage.getItem("#session_token");
return fetch("http://localhost:3333/api/1.0.0/search", {
headers: {
"X-Authorization": value,
},
})
.then((response) => {
if (response.status === 200) {
return response.json();
} else if (response.status === 401) {
props.navigation.navigate("Login");
} else {
throw "Something went wrong";
}
})
.then((responseJson) => {
setIsLoading(false);
setListData(responseJson);
})
.catch((error) => {
console.log(error);
});
};
const checkLoggedIn = async () => {
const value = await AsyncStorage.getItem("#session_token");
if (value == null) {
props.navigation.navigate("Login");
}
};
return (
<>
{isLoading ? (
<View
style={{
flex: 1,
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
}}
>
<Text>Loading..</Text>
</View>
) : (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<Text>Welcome to The app </Text>
<Button
title="Next Page"
onPress={() => {
props.navigation.navigate("yourScreenName");
}}
/>
</View>
)}
</>
);
};
export default HomeScreen;
since you screens are
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Login" component={LoginScreen} />
<Drawer.Screen name="Signup" component={SignupScreen} />
<Drawer.Screen name="Logout" component={LogoutScreen} />
//you can add more screens here just make sure to import them first
//example
<Drawer.Screen name="Example" component={ExampleScreen} />
// name will be the name you use to navigate to that screen
// component should have the screen you imported
then you should pass one of those names to props.navigation.navigate() so the button would be
<Button
title="Next Page"
onPress={() => {
props.navigation.navigate("Login");
}}
/>
If you want to stick with a class component, then :
import {TouchableOpacity} from "react-native"
In the else part,
<TouchableOpacity style ={{width:100, height:100}} onPress={()=>{this.props.navigation.navigate("screenname")}}></TouchableOpacity>
TouchableOpacity is a blank space on the screen, which can be styled easily, and you have an onPress event. Basically it's like a better version of a button. You can also place other components inside the TouchableOpacity, and make the whole thing clickable
Related
I am implementing a provider which helps me to have the state of my user in different views, the main function of this provider is to render different one or the other stack navigator depending on whether the variable is full or empty, this in order to be able to generate two groups of screens depending on whether the user is authenticated or not.
Here my code:
View router.tsx:
import { NavigationContainer } from "#react-navigation/native"
import React, { useContext, useEffect, useState, useRef } from "react"
import { UserContext } from "./context/Usuario"
import AuthStack from "./routes/AuthStack"
import GeneralStack from "./routes/GeneralStack"
const Router = () => {
const { me } = useContext(UserContext)
const auth = useRef(false)
useEffect(() => {
return () => {
auth.current = me !== null
console.log("Hola")
}
}, [me])
return (
<NavigationContainer>
{auth.current ? <GeneralStack /> : <AuthStack />}
</NavigationContainer>
)
}
export default Router
Provider user,js:
import React, { useEffect, createContext, useState } from "react"
import AsyncStorage from "#react-native-async-storage/async-storage"
export const UserContext = createContext()
const UserProvider = ({ children }) => {
const [me, setMe] = useState(undefined)
const validStorage = async () => {
try {
const miSesion = await AsyncStorage.getItem("sesion")
console.log(miSesion)
setMe(JSON.parse(miSesion))
} catch (error) {
console.log(`ERROR: ${error.message}`)
}
}
useEffect(() => {
validStorage()
}, [])
return (
<UserContext.Provider value={{ me, setMe }}>
{children}
</UserContext.Provider>
)
}
export default UserProvider
GeneralStack:
import { createNativeStackNavigator } from "#react-navigation/native-stack"
import React from "react"
import TabStack from "./TabStack"
//import TabStack from "./TabStack"
const GeneralScreen = createNativeStackNavigator()
const GeneralStack = () => {
return (
<GeneralScreen.Navigator screenOptions={{ headerShown: false }}>
<GeneralScreen.Screen name="Tabs" component={TabStack} />
</GeneralScreen.Navigator>
)
}
export default GeneralStack
AuthStack:
import { createNativeStackNavigator } from "#react-navigation/native-stack"
import React from "react"
import Login from "../Screens/Login"
import Registro from "../Screens/Registro/Registro"
import SplashScreen from "../SplashScreen"
const AuthScreen = createNativeStackNavigator()
const AuthStack = () => {
return (
<AuthScreen.Navigator
initialRouteName="Splash"
screenOptions={{ headerShown: false }}>
<AuthScreen.Screen name="Login" component={Login} />
<AuthScreen.Screen name="Register" component={Registro} />
<AuthScreen.Screen name="Splash" component={SplashScreen} />
</AuthScreen.Navigator>
)
}
export default AuthStack
Login:
import React, { useState, useContext } from "react"
import {
Image,
ScrollView,
StatusBar,
Text,
TouchableOpacity,
View,
} from "react-native"
import { useNavigate } from "../../Hooks/useNavigate"
import MyTextInput from "../../components/MyTextInput"
import colors from "../../styles/colors"
import { loginStyles } from "../../styles/styles"
import { UserContext } from "../../context/Usuario"
import AsyncStorage from "#react-native-async-storage/async-storage"
export default function Login() {
const [, setIsSession] = useState(false)
const { setMe } = useContext(UserContext)
const navigate = useNavigate()
const [hidePassword, sethidePassword] = React.useState(false)
const [user] = useState({ user: "admin", password: "admin123" })
const [form, setForm] = useState({ user: "", password: "" })
const getStorage = async () => {
if (await AsyncStorage.getItem("sesion")) {
setIsSession(true)
} else {
setIsSession(false)
}
}
const signIn = async () => {
try {
console.log(user)
if (form.user === user.user && form.password === user.password) {
await AsyncStorage.setItem("sesion", JSON.stringify(form))
setMe(form)
setIsSession(true)
}
} catch (error) {
console.error(error)
}
}
const closeSesion = async () => {
await AsyncStorage.removeItem("sesion")
getStorage()
}
return (
<ScrollView contentContainerStyle={[loginStyles.container]}>
<StatusBar backgroundColor={colors.PURPLE} translucent={true} />
<View style={loginStyles.logo}>
<Image
source={require("../../recursos/images/Logo.png")}
style={{ height: 250, width: 250 }}
/>
</View>
<MyTextInput
onChangeText={(text: string) => {
setForm(state => ({ ...state, user: text }))
}}
keyboardType="email-address"
placeholder="E-mail"
/>
<MyTextInput
onChangeText={(text: string) => {
setForm(state => ({ ...state, password: text }))
}}
keyboardType={null}
placeholder="Contraseña"
bolGone={true}
secureTextEntry={hidePassword}
onPress={() => sethidePassword(!hidePassword)}
/>
<View style={loginStyles.btnMain}>
<TouchableOpacity onPress={signIn}>
<Text style={loginStyles.btntxt}>Iniciar Sesión</Text>
</TouchableOpacity>
</View>
<View style={loginStyles.btnTransparent}>
<TouchableOpacity
onPress={() => navigate({ screen: "Register" })}>
<Text
style={[loginStyles.btntxt, { color: colors.PURPLE }]}>
Registrarse
</Text>
</TouchableOpacity>
</View>
<View>
<TouchableOpacity>
<Text
style={[
loginStyles.txtTransparent,
{ textDecorationLine: "none" },
]}>
Olvide mi contraseña
</Text>
</TouchableOpacity>
</View>
</ScrollView>
)
}
Home:
import AsyncStorage from "#react-native-async-storage/async-storage"
import React, { useState } from "react"
import { Image, ScrollView, TouchableOpacity } from "react-native"
import { Calendar } from "react-native-calendars"
import { Text } from "react-native-elements"
import { useNavigate } from "../../Hooks/useNavigate"
import colors from "../../styles/colors"
const Home = () => {
const [showModal, setShowModal] = useState(false)
const [date, setDate] = useState<string>()
const navigate = useNavigate()
const [isSession, setIsSession] = useState(false)
const getStorage = async () => {
const data = await AsyncStorage.getItem("sesion")
console.log(data)
if (data) {
setIsSession(true)
} else {
setIsSession(false)
}
}
const closeSesion = async () => {
await AsyncStorage.removeItem("sesion")
getStorage()
}
return (
<ScrollView>
<TouchableOpacity onPress={() => closeSesion()}>
<Text>Hola porque soy bien molon</Text>
</TouchableOpacity>
<Image
source={require("../../recursos/images/coralio_logo.png")}
style={{
marginTop: 40,
height: 110,
width: "80%",
justifyContent: "center",
alignSelf: "center",
}}
/>
<Calendar
theme={{
selectedDayBackgroundColor: colors.BLACK,
arrowColor: colors.WHITE,
monthTextColor: colors.WHITE,
}}
style={{
backgroundColor: colors.PURPLE,
borderRadius: 10,
elevation: 4,
marginTop: 60,
margin: 10,
height: 400,
}}
onDayPress={day => {
console.log(day.dateString)
setDate(day.dateString)
setShowModal(false)
}}
onMonthChange={() => {}}
initialDate={"2023-01-16"}
minDate={new Date()
.toLocaleDateString("es-US", {
year: "numeric",
month: "2-digit",
day: "numeric",
formatMatcher: "basic",
})
.split("/")
.reverse()
.join("-")}
markedDates={{
day: {
marked: true,
dotColor: colors.WHITE,
selected: true,
selectedColor: colors.PURPLE,
},
}}
//maxDate={"2023-12-31"}
//hideExtraDays={false}
//disableArrowLeft={true}
//disableArrowRight={true}
//hideArrows={true}
//hideDayNames={true}
/>
</ScrollView>
)
}
export default Home
The problem I have is when doing the close session in home, if in login it sends me from the authstack view to generalstack, when I do the close session it doesn't send me back to login, but it does clean the state of the variable from asyncstorage.
Help :(
It looks like you're not clearing the me variable in your context when the user ends the session. I think your closeSesion method should look like this:
const closeSesion = async () => {
setMe(null)
await AsyncStorage.removeItem("sesion")
getStorage()
}
I am new to this so I hope this is the right place to get help!
As titled, executing this code is giving me the "Too many re-renders" error on React.
I have tried going through all lines and checking my hooks repeatedly, but nothing seems to work.
I am guessing this is happening due to useEffect, so pasting the code for the relevant components below:
UseResults:
import { useEffect, useState } from 'react';
import yelp from '../api/yelp';
export default () => {
const [results, setResults] = useState([]);
const [errorMessage, setErrorMessage] = useState('');
const searchApi = async () => {
try {
const response = await yelp.get('/search', {
params: {
limit: 50,
term,
location: 'san francisco'
}
});
setResults(response.data.businesses);
} catch (err) {
setErrorMessage('Something went wrong')
}
};
useEffect(() => {
searchApi('pasta');
}, []);
return [searchApi, results, errorMessage];
}
SearchScreen:
import React, { useState } from 'react';
import { Text, StyleSheet } from 'react-native';
import { ScrollView } from 'react-native-gesture-handler';
import ResultsList from '../components/ResultsList';
import SearchBar from '../components/SearchBar';
import useResults from '../hooks/useResults';
const SearchScreen = (navigation) => {
const [term, setTerm] = useState('');
const [searchApi, results, errorMessage] = useResults();
const filterResultsByPrice = (price) => {
return results.filter(result => {
return result.price === price;
});
};
return <>
<SearchBar
term={term}
onTermChange={setTerm}
onTermSubmit={searchApi()}
/>
{errorMessage ? <Text>{errorMessage}</Text> : null}
<Text>We have found {results.length} results</Text>
<ScrollView>
<ResultsList
results={filterResultsByPrice('$')}
title="Cost Effective"
navigation={navigation}
/>
<ResultsList
results={filterResultsByPrice('$$')}
title="Bit Pricier"
navigation={navigation}
/>
<ResultsList
results={filterResultsByPrice('$$$')}
title="Big Spender"
navigation={navigation}
/>
</ScrollView>
</>
};
const styles = StyleSheet.create({});
export default SearchScreen;
ResultsList:
import React from 'react';
import { View, Text, StyleSheet, FlatList } from 'react-native';
import { TouchableOpacity } from 'react-native-gesture-handler';
import ResultsDetail from './ResultsDetail';
const ResultsList = ({ title, results, navigation }) => {
return (
<View style={styles.container} >
<Text style={styles.title}>{title}</Text>
<FlatList
horizontal
showsHorizontalScrollIndicator={false}
data={results}
keyExtractor={result => result.id}
renderItem={({ item }) => {
return (
<TouchableOpacity onPress={() => navigation.navigate('ResultsShow')}>
<ResultsDetail result={item} />
</TouchableOpacity>
)
}}
/>
</View>
);
};
const styles = StyleSheet.create({
title: {
fontSize: 18,
fontWeight: 'bold',
marginLeft: 15,
marginBottom: 5
},
container: {
marginBottom: 10
}
});
export default ResultsList;
TIA!
Flatlist component as below
<FlatList
data={this.state.data}
keyExtractor={item => item.ID.toString()}
renderItem={this.renderItem}
onRefresh={this.onRefresh}
refreshing={this.state.refreshing}
ListFooterComponent={this.renderFooter}
/>
renderItem = ({ item }) => {
return (
<ListElement onPress={() => this.rowData(item)} item={item}/>
);
};
ListItem Component
import React from "react";
import { Image } from "react-native";
import { Left, Right, Body, Text, ListItem } from "native-base";
import { widthPercentageToDP as wp, heightPercentageToDP as hp } from "react-native-responsive-screen";
import Thumbnails from "../components/Thumbnails";
import styles from "../styles/HomeStyles";
import GlobalStyles from "../constants/GlobalStyles";
class ListElement extends React.Component {
componentDidMount(){
console.log(this.props.item.ID)
}
shouldComponentUpdate(){
return false;
}
render() {
return (
<ListItem onPress={this.props.onPress} thumbnail style={styles.listItem}>
<Left>
<Thumbnails imageURI={require("../../assets/images/female2.png")} />
</Left>
<Body style={{ borderBottomColor: "transparent", top: 2 }}>
<Text
style={{
fontFamily: GlobalStyles.primaryFont,
fontSize: hp("1.85%"),
}}
>
{this.props.item.FirstName} {this.props.item.LastName}
</Text>
<Text
note
style={{
fontFamily: GlobalStyles.primaryFont,
color: "#666666",
fontSize: hp("1.6%"),
}}
>
{this.props.item.Title}
</Text>
</Body>
<Right>
<Image
style={styles.rightArrow}
source={require("../../assets/images/arrowRight.png")}
/>
</Right>
</ListItem>
);
}
}
export default ListElement;
I tried to populate api data on the flatlist. Please refer my above code for implementation. Currently I am facing rerendering issues as mentioned below.
My listitem componentDidMount is invoking multiple times on scroll after even intial render of all listitems.
I have tried PureComponent and shouldComponentUpdate. Thanks in advance.
An Update
Please Find the entire code of Flatlist component
import React, { PureComponent } from "react";
import { View, FlatList } from "react-native";
import { ListItem } from "react-native-elements";
import FL from "../screens/FL";
import FL1 from "../screens/Fl1";
class FlatListDemo extends PureComponent {
constructor(props) {
super(props);
this.state = {
loading: false,
data: [],
error: null,
refreshing: false,
};
}
componentDidMount() {
this.makeRemoteRequest();
}
makeRemoteRequest = () => {
const url = `https://jsonplaceholder.typicode.com/posts`;
this.setState({ loading: true });
fetch(url)
.then((res) => res.json())
.then((res) => {
this.setState({
data: res,
error: res.error || null,
loading: false,
refreshing: false,
});
})
.catch((error) => {
this.setState({ error, loading: false });
});
};
renderItem = ({ item }) => {
return <ListElement onPress={() => this.rowData(item)} item={item} />;
};
render() {
if (this.state.loading === true) {
return <View></View>;
} else {
return (
<View>
<FlatList
data={this.state.data}
keyExtractor={(item) => item.ID.toString()}
renderItem={this.renderItem}
onRefresh={this.onRefresh}
refreshing={this.state.refreshing}
ListFooterComponent={this.renderFooter}
/>
</View>
);
}
}
}
export default FlatListDemo;
Try the following:
add to state a boolean value (you can name it "wasFetched").
Then change the componentDidMount like this:
componentDidMount() {
if(this.state.wasFetched === false) {
this.setState({ wasFetched: true }, () => this.makeRemoteRequest())
}
}
App has all old code which I am upgrading to latest versions. It was using Redux for state management with StackNavigator. Since that is not supported, I am not able to understand how to migrate my existing redux actions, which were changing screens on various events.
An example action:
export const goToHome = () => ({
type: PUSH,
routeName: 'projectList',
});
Which earlier reached navReducer, which handled POPing and PUSHing of screens.
export default (state = initialState, action) => {
let nextState;
switch (action.type) {
case NAV_POP:
nextState = AppNavigator.router.getStateForAction(
NavigationActions.goBack(),
state
);
break;
...
Please suggest.
Thanks.
The navigationRef is used for the scenarios like this.
You can refer the documentation here
It states
Sometimes you need to trigger a navigation action from places where
you do not have access to the navigation prop, such as a Redux
middleware. For such cases, you can dispatch navigation actions from
the navigation container
Which exactly is your requirement, here we create a navigationref and use call the navigation methods from there.
The below is the code for a simple example, you can use the 'navigate' inside your reducer. Also you will have to move it to a separate file just like they've provided in the documetation.
import * as React from 'react';
import { View, Button, Text } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
const navigationRef = React.createRef();
function navigate(name, params) {
navigationRef.current && navigationRef.current.navigate(name, params);
}
function Home() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
title="Go to Settings"
onPress={() => navigate('Settings', { userName: 'Lucy' })}
/>
</View>
);
}
function Settings({ route }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Hello {route.params.userName}</Text>
<Button title="Go to Home" onPress={() => navigate('Home')} />
</View>
);
}
const RootStack = createStackNavigator();
export default function App() {
return (
<NavigationContainer ref={navigationRef}>
<RootStack.Navigator>
<RootStack.Screen name="Home" component={Home} />
<RootStack.Screen name="Settings" component={Settings} />
</RootStack.Navigator>
</NavigationContainer>
);
}
you can navigate through navigation container ref
you can call navigation().navigate("Settings") or navigation().goBack() in reducer
here is the demo of export navigation: https://snack.expo.io/#nomi9995/2eb7fd
App.js
import React,{useEffect} from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
const navRef = React.createRef();
export const navigation=()=>{
return navRef.current && navRef.current
}
const TestComponent=()=> {
useEffect(()=>{
setTimeout(() => {
navigation().navigate("Settings")
setTimeout(() => {
navigation().goBack()
}, 3000);
}, 100);
})
return (
<View style={styles.container}>
<Text>TestComponent 1</Text>
</View>
);
}
const TestComponent2=()=> {
return (
<View style={styles.container}>
<Text>TestComponent 2</Text>
</View>
);
}
const RootStack = createStackNavigator();
export default function App() {
return (
<NavigationContainer ref={navRef}>
<RootStack.Navigator>
<RootStack.Screen name="Home" component={TestComponent} />
<RootStack.Screen name="Settings" component={TestComponent2} />
</RootStack.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
reducder.js
import { navigation } from 'path of App.js';
export default (state = initialState, action) => {
let nextState;
switch (action.type) {
case NAV_POP:
nextState = navigation().goBack()
break;
I am now using React native navigation 5 and in my "Home component I have a setParams which works but I get that error:
"The action 'SET_PARAMS' with the payload {"params":{"company":"Marciello Resto 2"}} was not handled by any navigator."
I am on Android Emulator.
Thank you all for your help!
//App.js
import * as React from "react"
import { View, Text, ActivityIndicator, StyleSheet } from 'react-native'
import { NavigationContainer } from '#react-navigation/native'
import { createStackNavigator } from '#react-navigation/stack'
import { createDrawerNavigator } from '#react-navigation/drawer'
import EtiquettesPictureContext from './Components/Contexts/EtiquettesPictureContext'
import RootStack from './Navigation/Navigation'
import Home from './Components/Layouts/Home'
import Etiquettes from './Components/Layouts/Etiquettes'
import TemperaturesFridges from './Components/Layouts/TemperaturesFridges'
import BonsLivraisons from './Components/Layouts/BonsLivraisons'
import EtiquettesTakePicture from "./Components/EtiquettesTakePicture"
import BonsLivraisonsTakePicture from "./Components/BonsLivraisonsTakePicture"
import DlcAlertTakePicture from "./Components/DlcAlertTakePicture"
import Notifications from "./Components/Layouts/Notifications"
import Settings from "./Components/Layouts/Settings"
import Welcome from "./Components/Layouts/Welcome"
import Login from "./Components/Layouts/Login"
import Signup from "./Components/Layouts/Signup"
import InitLogin from "./Components/Layouts/InitLogin"
import MesEtiquettes from "./Components/Layouts/MesEtiquettes"
import WhatRole from "./Components/WhatRole"
const AuthContext = React.createContext()
const Stack = createStackNavigator()
const Drawer = createDrawerNavigator()
export default function App({ navigation }) {
const [etiquettesPictureData, blPictureData, setEtiquettesPictureData, setBlPictureData] = React.useState("")
updateInitialData = (data) => {
setEtiquettesPictureData(data)
}
updateBlData = (data) => {
blPictureData(data)
}
const [state, dispatch] = React.useReducer(
(prevState, action) => {
switch (action.type) {
case 'RESTORE_TOKEN':
return {
...prevState,
userToken: action.isLogged,
isLoading: false,
};
case 'SIGN_IN':
return {
...prevState,
isSignout: false,
userToken: action.isLogged,
};
case 'SIGN_OUT':
return {
...prevState,
isSignout: true,
userToken: null,
};
}
},
{
isLoading: true,
isSignout: false,
userToken: null,
}
);
React.useEffect(() => {
// Fetch the token from storage then navigate to our appropriate place
const bootstrapAsync = async () => {
let isLogged;
try {
isLogged = await InitLogin.initLogin()
} catch (e) {
// Restoring token failed
}
// After restoring token, we may need to validate it in production apps
// This will switch to the App screen or Auth screen and this loading
// screen will be unmounted and thrown away.
dispatch({ type: 'RESTORE_TOKEN', isLogged: isLogged.logged });
};
bootstrapAsync();
}, []);
const authContext = React.useMemo(
() => ({
signIn: async data => {
// In a production app, we need to send some data (usually username, password) to server and get a token
// We will also need to handle errors if sign in failed
// After getting token, we need to persist the token using AsyncStorage
// In the example, we'll use a dummy token
dispatch({ type: 'SIGN_IN', isLogged: 'dummy-auth-token' });
},
signOut: () => dispatch({ type: 'SIGN_OUT' }),
signUp: async data => {
// In a production app, we need to send user data to server and get a token
// We will also need to handle errors if sign up failed
// After getting token, we need to persist the token using `AsyncStorage`
// In the example, we'll use a dummy token
dispatch({ type: 'SIGN_IN', isLogged: 'dummy-auth-token' });
},
}),
[]
)
if (state.isLoading) {
// We haven't finished checking for the token yet
return (
<View style={[styles.container, styles.horizontal]}>
)
}
function RootStackScreen() {
return (
<Stack.Navigator>
{state.userToken == false ? (
<>
<Stack.Screen name="Welcome" component={Welcome} />
<Stack.Screen name="Login" component={Login} />
<Stack.Screen name="Signup" component={Signup} />
</>
) : (
<>
<Stack.Screen name="Home" component={Home} options={({ route }) => ({ title: route.params ? route.params.company : "" })} />
<Stack.Screen name="Etiquettes" component={Etiquettes} />
<Stack.Screen name="TemperaturesFridges" component={TemperaturesFridges} />
</>
)}
</Stack.Navigator>
)
}
function DrawerScreen() {
return (
<Drawer.Navigator>
<Drawer.Screen name="TemperaturesFridges" component={TemperaturesFridges} />
</Drawer.Navigator>
)
}
return (
<EtiquettesPictureContext.Provider
value={{
etiquette: etiquettesPictureData,
Bl: blPictureData,
updateInitialData: updateInitialData,
updateBlData: updateBlData
}}>
<AuthContext.Provider value={authContext}>
<Drawer.Navigator>
<Drawer.Screen name="Home" component={RootStackScreen} />
</Drawer.Navigator>
</AuthContext.Provider>
</EtiquettesPictureContext.Provider>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center'
},
horizontal: {
flexDirection: 'row',
justifyContent: 'space-around',
padding: 10
}
})
//Home.jsimport * as React from 'react';
import mainStyleSheet from "../../Themes/main.js"
import { MaterialHeaderButtons, Item} from '../HeaderButtons';
import Ionicons from 'react-native-vector-icons/FontAwesome5';
import Company from '../Entities/Company';
import Notification from '../Entities/Notification'
import {
SafeAreaView,
ScrollView,
View,
Text,
TouchableHighlight
} from 'react-native';
export default function Home({ navigation}) {
React.useEffect(() => {
Company.getCompany().then(company => {
navigation.setParams({ company })
})
this.didBlurSubscription = navigation.addListener(
'didFocus',
() => {
Notification.countNotifications()
.then(resp => {
navigation.setParams({ notificationsCount: resp.length })
})
}
)
// returned function will be called on component unmount
return () => {
this.didBlurSubscription()
}
}, [])
const { navigate} = navigation;
return (
<TouchableHighlight style={[mainStyleSheet.buttonHomeContainer, { marginTop: 0 }]} onPress={() => navigate('Etiquettes')} >
<Ionicons name="tag" style={{ marginLeft: 20 }} color="white" size={30} />
Etiquettes produits
<TouchableHighlight style={mainStyleSheet.buttonHomeContainer} onPress={() => navigate('TemperaturesFridges')}>
<Ionicons name="thermometer-quarter" style={{ marginLeft: 20 }} color="white" size={30} />
Relevés de température
<TouchableHighlight style={mainStyleSheet.buttonHomeContainer} onPress={() => navigate('BonsLivraisons')}>
<Ionicons name="file-invoice" style={{ marginLeft: 20 }} color="white" size={30} />
Bons de livraisons
<TouchableHighlight style={mainStyleSheet.buttonHomeContainer} onPress={() => navigate('DownloadableDocuments')}>
<Ionicons name="file-image" style={{ marginLeft: 20 }} color="white" size={30} />
Documents à télécharger
)
}
I believe this issue has to do with calling navigation.setParams when the component is unmounting. According to the react navigation docs [0],
The setParams method lets us update the params (route.params) of the current screen
If the current screen is already unmounting when setParams gets called, then it would make sense that the navigator would not be able to handle it. Rework your logic so you are not setting params on blur.
[0] https://reactnavigation.org/docs/navigation-prop/#setparams