I set up Auth0 in React Native (using Expo iOS app Xcode simulator). When "login" is invoked, it doesn't run "authorize()". It's not taking me to the Auth0 login page. For my callback URL in Auth0, I set it to localhost:19000 (which is the same as my expo-client).
import React from 'react';
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Button, Text, View } from 'react-native';
import {useAuth0, Auth0Provider} from 'react-native-auth0';
const Home = () => {
const {authorize, clearSession, user} = useAuth0();
const login = async () => {
try {
await authorize();
} catch (err) {
console.log(err);
}
}
const onLogout = async () => {
try {
await clearSession();
} catch (err) {
console.log('log out canceled');
}
}
return (
<View style={styles.container}>
{!user && <Button onPress={login} title="Log in" />}
{user && <Text>Logged in as {user.name}</Text>}
</View>
)
}
const App = () => {
return (
<Auth0Provider domain={"ihavemydomainhere} clientId={"ihavemyclientidhere"}>
<Home />
</Auth0Provider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
alignItems: 'center',
justifyContent: 'center',
},
});
export default App;
react-native-auth0 use native code which is not compatible with Expo Go. That’s why is not doing anything. Try building a dev build, that should work.
Source: https://auth0.com/docs/quickstart/native/react-native-expo/interactive (the WARN message states “ This SDK is not compatible with "Expo Go" app. It is compatible only with Custom Dev Client and EAS builds.”)
Hope that helps
Related
Why my app is only showing loading screen? when i am running my app than its only loading and not showing other screens and showing a WARN that
` WARN Possible Unhandled Promise Rejection (id: 0): TypeError: undefined is
i think it has problem with this code
import React, { useEffect } from 'react';
import { View, ActivityIndicator, StyleSheet} from 'react-native';
import { AsyncStorage } from '#react-native-async-storage/async-storage';
import { useDispatch } from 'react-redux';
import Colors from '../constants/Colors';
import * as authActions from '../store/actions/auth';
const StartupScreen = props => {
const dispatch = useDispatch();
useEffect(() => {
const tryLogin = async () => {
const userData = await AsyncStorage.getItem('userData');
if (!userData) {
// props.navigation.navigate('Auth');
dispatch(authActions.setDidTryAutoLogin());
return;
}
const transformedData = JSON.parse(userData);
const { token, user } = transformedData;
// props.navigation.navigate('Shop');
dispatch(authActions.authenticate(user, token));
};
tryLogin();
}, [dispatch])
return (
<View style={styles.screen}>
<ActivityIndicator size="large" color={Colors.primary} />
</View>
);
};
const styles = StyleSheet.create({
screen: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
});
export default StartupScreen;
According to the docs you import is wrong.
This:
import { AsyncStorage } from '#react-native-async-storage/async-storage';
should be
import AsyncStorage from '#react-native-async-storage/async-storage';
Basically, what you are trying to do with {AsyncStorage} is you are importing "part" of the exported code called AsyncStorage. That is why the error says:
_asyncStorage.AsyncStorage.getItem') (asyncStorage mentioned twice) and you need the entire object out of the package.
Hi I am implementing react navigation in a react native app, and I am following the docs on react navigation. And I when I run the code this is the result:
My question is how do I make the center content's width same as the screen.
Also, his is my first time using react native expo after switching from reactJS
Code:
navigator code:
import Login from "./Login";
import Signup from "./Signup";
import {
createAppContainer,
NavigationContainer,
NavigationNavigator,
} from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import Chat from "./Chat";
import Error from "./Error";
/**
* This is the screen stack of the navigation stack.
*/
const screens: any = {
default: { screen: Login },
signup: { screen: Signup },
chat: { screen: Chat },
Error: { screen: Error },
};
const stack: NavigationNavigator<any, any> = createStackNavigator(screens);
const container: NavigationContainer = createAppContainer(stack);
export default container;
App.tsx:
import { StatusBar } from "expo-status-bar";
import React from "react";
import { Alert, StyleSheet, Text, View } from "react-native";
import * as expoAppLoading from "expo-app-loading";
import loadFonts from "./assets/fonts/loader";
import Navigator from "./screens/navigator";
/**
* This is the main app component of the Chill&chat application.
*/
const App: React.FC = () => {
const [loading, setLoading] = React.useState(true);
const style: any = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
text: {
fontFamily: "poppinsBold",
},
});
if (loading) {
return (
<expoAppLoading.default
startAsync={async (): Promise<void> => {
await loadFonts();
}}
onFinish={(): void => {
setLoading(false);
}}
onError={(): void => {
Alert.alert("Error", "Error loading fonts");
}}
/>
);
} else {
return (
<View style={style.container}>
<Navigator />
<StatusBar style="auto" />
</View>
);
}
};
export default App;
You should be able to set the width by adding percentage dimensions to your style sheet for the desired element. This may require you do away with flex layout however, or use flex in a parent instead.
container: {
width:'100%',
},
This should solve for the width problem though.
I'm using https://github.com/expo-community/expo-firebase-starter as a starter template to build a react native app using firebase.
I am working with the following file in Home.js and want to save data to firebase but am getting an error. The error.
firebase.database is not a function. (In 'firebase.database(reflection)', 'firebase.database' is undefined)
Here is the code I'm using. When someone writes a reflection, I'm trying to save that reflection text along with the user ID.
import React, {useEffect, useState } from "react";
import { StyleSheet, Text, View } from "react-native";
import { Container, Content, Header, Form, Input, Item, Label } from 'native-base';
import { Button } from "react-native-elements";
import { withFirebaseHOC } from "../config/Firebase";
import * as firebase from 'firebase';
import "firebase/database";
function Home({ navigation, firebase }) {
const [reflection, setReflection] = useState('');
const[member, setMember] = useState('');
useEffect(() => {
try {
firebase.checkUserAuth(user => {
if (user) {
// if the user has previously logged in
setMember(user);
console.log(member);
} else {
// if the user has previously logged out from the app
navigation.navigate("Auth");
}
});
} catch (error) {
console.log(error);
}
}, []);
async function postReflection() {
try {
await console.log(reflection);
await console.log(member.email);
firebase.database(reflection).ref('Posts/').set({
reflection,
}).then((data)=>{
//success callback
console.log('data ' , data)
}).catch((error)=>{
//error callback
console.log('error ' , error)
})
} catch (error) {
console.log(error);
}
}
async function handleSignout() {
try {
await firebase.signOut();
navigation.navigate("Auth");
} catch (error) {
console.log(error);
}
}
return (
<Container style={styles.container}>
<Form>
<Item floatingLabel>
<Label>Reflection</Label>
<Input
autoCapitalize='none'
autoCorrect={false}
onChangeText={text => setReflection(text)}
/>
</Item>
<Button style = {{ marginTop: 10, marginHorizontal:30 }}
title="Share"
rounded
onPress= {postReflection}
>
</Button>
</Form>
<Button
title="Signout"
onPress={handleSignout}
titleStyle={{
color: "#F57C00"
}}
type="clear"
/>
</Container>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
// justifyContent: "center"
}
});
export default withFirebaseHOC(Home);
Your /config/Firebase/firebase.js doesn't have a database property. Have a look at how the Firebase object is being exported.
// inside /config/Firebase/firebase.js
import "firebase/database"; // add this
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
const Firebase = {
// add this
database: () => {
return firebase.database()
}
};
export default Firebase;
Have a read of this step. You can't just import the part of the firebase library, you need to actually assign it to a variable and export it to use it.
https://firebase.google.com/docs/web/setup#namespace
Add the following after import * as firebase from 'firebase';
import "firebase/database";
Each Firebase product has separate APIs that must be added, as described in the documentation.
I am trying different ways to display a conditional button based on the athtentication state, but i keep getting into trouble. I have an app.js that defines the stacknavigator, which adds a button to the header giving the option to log out if authenticated.
I wrote a handleLogout function that should perform this.
import React from 'react';
import { Button, Image, View, Text } from 'react-native';
import firebase from 'react-native-firebase';
import Loading from './Loading';
import SignUp from './SignUp';
import Login from './Login';
import Main from './Main';
import {createAppContainer} from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';
import { useNavigation } from '#react-navigation/native';
// eslint-disable-next-line no-undef
handleLogOut = () => {
const navigation = useNavigation();
firebase
.auth()
.signOut()
.then(() => this.props.navigation.navigate('Login'))
.catch(error => this.setState({errorMessage: error.message}));
};
const AppNavigator = createStackNavigator(
{
Loading: Loading,
SignUp: SignUp,
Login: Login,
Main: Main,
},
{
initialRouteName: 'Loading',
defaultNavigationOptions: {
headerLeft: null,
headerRight: () => {
let button = this.loggedIn? (
<Button
onPress={this.handleLogOut}
title="Log-out"
color="#fff"
/>
)
:
(
<Button
onPress={() => alert('Please log in')}
title="Log-in"
color="#fff"
/>
)
return button;
},
headerStyle: {
backgroundColor: '#c6f1e7',
},
headerTintColor: '#59616e',
headerTitleStyle: {
fontFamily: 'Raleway-Regular',
fontWeight: '400',
},
},
},
);
export default createAppContainer(AppNavigator);
App.js calls on loading.js where the value for loggedin is declared, based on the authentciation state and then loads either main.js or sign-up. in this case the main page is loaded, which means that someone is authenticated:
// Loading.js
import React from 'react';
import {View, ActivityIndicator, StyleSheet} from 'react-native';
import firebase from 'react-native-firebase';
export default class Loading extends React.Component {
componentDidMount() {
firebase.auth().onAuthStateChanged(user => {
if (user) {
this.setState({ loggedIn: true })
this.props.navigation.navigate(user ? 'Main' : 'SignUp');
} else {
this.setState({ loggedIn: false })
}
});
}
render() {
return (
<View style={styles.container}>
<ActivityIndicator size="large" />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#c6f1e7',
},
});
Now the page redirects to main and shows the welcome message, which indicates that the user is logged in, but the button in the header is saying 'log-in' as well, which means the button is not chosen well. I assume that this is because the loggedin value is not read and it automatically sets it on loggedin: false.
Here is the code for main.js
// Main.js
import React from 'react';
import { View, Text, StyleSheet, Button } from 'react-native';
import firebase from 'react-native-firebase';
import { createAppContainer } from 'react-navigation';
import { createBottomTabNavigator } from 'react-navigation-tabs';
import Kowops from './Kowops';
import Scan from './Scan';
import Wallet from './Wallet';
export class Main extends React.Component {
state = { currentUser: null }
componentDidMount() {
const { currentUser } = firebase.auth()
this.setState({ currentUser })
}
render() {
const { currentUser } = this.state
return (
<View style={styles.container}>
<Text>
Hidiho {currentUser && currentUser.email}!
</Text>
</View>
)
}
}
const bottomTabNavigator = createBottomTabNavigator(
{
Main: {screen: Main},
Kowops: {screen:Kowops},
Scan: {screen:Scan},
Wallet: {screen:Wallet},
},
{
//initialRouteName: 'Main',
tabBarOptions: {
initialRouteName: 'Main',
activeTintColor: '#59616e',
inactiveTintColor: '#a9a9a9',
style: {
backgroundColor: '#c6f1e7',
}
},
});
export default createAppContainer(bottomTabNavigator);
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
})
So I need to figure out how to ensure that the value of isloggedin is read properly and the script loads the right button.
Does anyone have a clue?
Thanks in advance!!
Tim
The key here is that you can't use state across different components without passing them as props or through navigation params in this case. You can't use the useNavigation hook outside of a functional component so you should pass the navigation object around when you need it outside of a component (handleLogout is not a component).
Here are some alterations I would make, however I would suggest that you will need to make further changes based on the idea that you can use navigation params to pass information between screens. See more here https://reactnavigation.org/docs/en/params.html.
App.js
DefaultNavigationOptions can be a function which has a navigation prop, this is the navigation object you can use to get params or navigate in the context of the router.
remove that eslint exception because you don't need it, just properly declare the variable. Remove the "this" from you handleLogout function call because it is not a class attribute. Use navigation.getParam to get the isLoggedIn variable which you can pass in the navigate function call.
const handleLogout = navigation => {
firebase
.auth()
.signOut()
.then(() => navigation.navigate('Login'))
.catch(error => this.setState({errorMessage: error.message}));
}
...
defaultNavigationOptions: ({navigation}) => ({
headerRight: () => {
const isLoggedIn = navigation.getParam('isLoggedIn', false);
let button = isLoggedIn ? (
<Button
onPress={() => handleLogOut(navigation)}
title="Log-out"
color="#fff"
/>
) : ...
} ...
Now Loading.js
Here you need to add a navigation param to your navigate call which can then be used in the header
...
firebase.auth().onAuthStateChanged(user => {
if (user) {
this.props.navigation.navigate('Main', {isLoggedIn: true});
} else {
this.props.navigation.navigate('SignUp', {isLoggedIn: false});
}
});
here is a modified version of your code in snack that you can see will get the logged in param and show the logout button https://snack.expo.io/#dannyhw/intrigued-graham-crackers
You will need to make further changes to fix other functionality because I only changed the minimum to show that you can use the navigation param.
I try to load a fontfamily, I used hook with async function but I have some errors:
function Button(props: TouchableOpacityProps & ButtonProps) {
useEffect(() => {
async function loadFont() {
await Font.loadAsync({
gotham_medium: require("../../assets/GothamMedium_1.ttf")
});
}
loadFont()
}, []);
return (
<TouchableOpacity {...props} style={styles.button}>
<Text style={styles.title}>{props.title}</Text>
</TouchableOpacity>
);
};
I imported Font from expo and useEffect from react but I have this error.
error on the device
This is what I have on my app in case it may help someone.
useEffect(() => {
const loadFonts = async () => {
await Font.loadAsync({
'pokeh': require('../../assets/fonts/pokeh.ttf'),
});
setFontReady(true);
};
loadFonts();
}, []);
And these two on the top after installing expo-font with npm
import * as Font from 'expo-font';
import { AppLoading } from 'expo';
Under this tree structure:
Your error might be generated by the wrong React version. Are you sure you're using at least Expo SDK 33?
If that's not the issue, I believe it might be easier if you load all assets earlier in the process. Expo provides an AppLoading component that takes a startAsync prop, which can be used to resolve all async promises pretty easily.
So your App.js could look like:
import { AppLoading } from 'expo';
import * as Font from 'expo-font';
import React, { useState } from 'react';
import { StyleSheet, View, Text } from 'react-native';
export default function App(props) {
const [isLoadingComplete, setLoadingComplete] = useState(false);
if (!isLoadingComplete && !props.skipLoadingScreen) {
return (
<AppLoading
startAsync={loadResourcesAsync}
onError={handleLoadingError}
onFinish={() => handleFinishLoading(setLoadingComplete)}
/>
);
} else {
return (
<View style={styles.container}>
<Text style={styles.title}>Welcome to your Expo app</Text>
</View>
);
}
}
async function loadResourcesAsync() {
await Promise.all([
Font.loadAsync({
'gotham-medium': require('./assets/GothamMedium_1.ttf')
}),
]);
}
function handleLoadingError(error) {
console.warn(error);
}
function handleFinishLoading(setLoadingComplete) {
setLoadingComplete(true);
}
const styles = StyleSheet.create({
container: {
marginTop: 60,
flex: 1,
backgroundColor: '#fff',
},
title: {
fontFamily: 'gotham-medium',
fontSize: 36
}
});
and then you have access to fontFamily: 'gotham-medium' anywhere in your app. Also you can resolve multiple promises (load other assets, etc.) within the Promise.all() call.
Let me know if that helped. Cheers!