Redirecting user based on his authentication - react-native

In my react native application, I want to check if a user has already logged in before, then he must be redirected to 'Home' directly without asking him for credentials again. The 'Home' component consists of logout button in a sidebar.
My current code works fine for new user logging, but I am stuck on how to check if again the user open the application, his login token should persist and he must be redirected to 'Home' directly.
Here is my code:
import React, { Component } from 'react'
import { Text, View, Image, TextInput, TouchableOpacity, ScrollView, AsyncStorage, ToastAndroid } from 'react-native'
import axios from 'axios';
export default class Login extends Component {
constructor(){
super();
this.state = {
username: '',
password: '',
isLoggedIn: false,
loginChecked: false,
}
}
componentDidMount(){
this.getItem('userID');
}
//function to extract storage token. Any name can be given ot it.
async getItem(item){
console.log('method ran login screen');
console.log(this.state.isLoggedIn)
try{
const value = await AsyncStorage.getItem(item);
if(value !== null){
this.setState({
isLoggedIn: true,
loginChecked: true
})
}
else{
this.setState({
isLoggedIn: false,
loginChecked: true
})
}
}
catch(error){
console.log(error)
}
console.log(this.state.isLoggedIn)
}
//function to remove storage token
async removeItem(item){
try{
const value = await AsyncStorage.removeItem(item);
if(value == null){
this.setState({
isLoggedIn: false
})
}
}
catch(error){
//handle errors here
}
}
userLogin = () => {
if(this.state.username != '' && this.state.password != ''){
axios.post('http://bi.servassure.net/api/login', {
username: this.state.username,
password: this.state.password
})
.then(res => {
let userToken = res.data.token;
console.log(res.data);
if(res.data.success){
AsyncStorage.setItem('userID', userToken);
this.setState({
isLoggedIn: true
})
this.props.navigation.navigate('Home');
}
else{
ToastAndroid.showWithGravity(
'Invalid login' ,
ToastAndroid.SHORT,
ToastAndroid.CENTER
);
}
})
.catch(err => {
console.log(err);
});
}
else{
ToastAndroid.showWithGravity(
'Please Enter Credentials' ,
ToastAndroid.SHORT,
ToastAndroid.CENTER
);
}
}
logOut(){
this.removeItem('userID');
}
render() {
return (
<ScrollView>
<View style={{justifyContent:'center', alignItems:'center'}}>
<View style={{marginVertical:20}}>
<Text>
Login to your account
</Text>
</View>
<View>
<TextInput
style={{width: 300, height: 50, borderColor: 'gray', borderWidth: 1, borderRadius: 10, marginVertical: 10}}
onChangeText={(username) => this.setState({username})}
placeholder='username'
autoCapitalize = 'none'
/>
<TextInput
style={{width: 300, height: 50, borderColor: 'gray', borderWidth: 1, borderRadius: 10}}
onChangeText={(password) => this.setState({password})}
placeholder='password'
secureTextEntry={true}
/>
</View>
<View style={{justifyContent: 'center', alignItems: 'center'}}>
<TouchableOpacity
style={{width: 300, height: 50, borderWidth:1, borderRadius: 50, borderColor: 'gray', justifyContent: 'center', alignItems: 'center', marginVertical: 10}}
onPress={this.userLogin}>
<Text>
LOGIN
</Text>
</TouchableOpacity>
<Text>Forget Password</Text>
</View>
</View>
</ScrollView>
)
}
}
Also, I have a SplashScreen before login:
import React, { Component } from 'react'
import { Text, View } from 'react-native'
export default class SplashScreen extends Component {
componentDidMount(){
setTimeout( () => {
this.props.navigation.navigate('Login')
}, 2000)
}
render() {
return (
<View style={styles.viewStyles}>
<Text style={styles.textStyles}> My App </Text>
</View>
)
}
}
const styles = {
viewStyles: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'orange'
},
textStyles: {
color: 'white',
fontSize: 40,
fontWeight: 'bold'
}
}
I am bit new to react native, please help to figure this out.

Do something like this in your Login.js file:
import {AsyncStorage} from react-native;
After getting the response success of login API you can do this:
AsyncStorage.setItem('userID', responsejson.user_detail.userID);
in the same way, you can store the token also
AsyncStorage.setItem('token', responsejson.user_detail.token);
Then in your splashscreen.js, import AsyncStorage the same way as above and then place this code in componentWillMount() or componentDidMount()
of your splashscreen.js
var value = AsyncStorage.getItem('token');
value.then((e)=>{
if (e == '' || e == null ){
this.props.navigation.replace('Login')
}else {
this.props.navigation.replace('Home')
}
})
Explanation: When splashscreen.js is loaded then it checks for the token in asyncstorage and if it gets the token navigate to Home screen else navigate to Login screen.

Import the React Navigation library and use the Switch Navigator. It was designed to handle app navigation based on the login status of the user.
This article explains everything with examples

Related

Want to transfer login status from store to Login Screen for wrong credentials identification

I have to React Native IOS App with Login Screen for users. In the store auth, I am getting string output from Login API as 'success' or 'Login Failed'.I want to transfer this login status to Login Screen, to tell the user about the wrong credentials. Below is the auth store:
auth.js:
export const LOGIN ='LOGIN';
export const login=(textemailid,textpassword) =>{
const formData = new FormData();
formData.append('txtUemail',textemailid);
formData.append('txtUpass',textpassword);
return async dispatch =>{
await fetch('https:/-------------------/login.php',
{
method:'post',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: formData
})
.then(res => res.text())
.then(
(loginresult) =>{
var login = loginresult.replace('\r\n\r\n\r\n\t\r\n\t\r\n\t','');
console.log('loginstatus is '+login);
}).catch(err =>{
console.log(err);
})
dispatch({type:LOGIN,loginStatus:login});
}
}
I want to transfer the 'login' value to Login Screen using navigation. Below is the LoginScreen code:
LoginScreen.js:
import React,{useEffect} from 'react';
import { ActivityIndicator,StyleSheet, Text, View
,KeyboardAvoidingView,TouchableOpacity,Image} from "react-native";
import { Button } from 'react-native-elements';
import { ScrollView } from "react-native-gesture-handler";
import { HelperText,TextInput } from 'react-native-paper';
import { useDispatch } from 'react-redux';
import * as authActions from '../../store/actions/auth';
import Icon from 'react-native-vector-icons/FontAwesome5';
import AsyncStorage from '#react-native-async-storage/async-
storage'
import Toast from 'react-native-root-toast';
const LoginScreen = ({route}) => {
const [textemailid, setTextEmailId] = React.useState('');
const [textpassword, setTextPassword] = React.useState('');
const [isLoading,setIsLoading] = React.useState(false);
const [error, setError] = React.useState('');
const dispatch = useDispatch();
const loginStatus1 = useSelector(state =>
state?.auth?.login_Status); **getting login_Status from auth reducer**
//console.log(state);
console.log('login status is '+loginStatus1)
const loginHandler = async () => {
let action
action = authActions.login(
textemailid,
textpassword
);
setError(null);
setIsLoading(true);
try{
dispatch(action);
console.log('login status is '+loginStatus);
if(loginStatus === 'Login Failed'){
let toast_success = Toast.show('Wrong Credentials');
setIsLoading(false);
}
else if(loginStatus === 'success'){
props.navigation.navigate({routeName:'Home'});
}
} catch(err){
setError(err.message);
console.log(err.message);
setIsLoading(false);
}
};
return(
<KeyboardAvoidingView style={styles.container}>
<ScrollView>
<View style={styles.container}>
<View style={styles.subView}>
<Image
style={{flex:1, height: 100, width: 100,alignSelf:'center',bottom:350}}
source={require('../../assets/profile1.png')}
resizeMode="contain"
/>
<View style={styles.welcometextview}>
<Text style={styles.welcometext}>Welcome!</Text>
{/* <Loader loading={isLoading} color="#ff66be" title='Loading'/> */}
</View>
<View style={styles.textinputemailview}>
<TextInput
underlineColor='grey'
style={styles.textinputemail}
label='Email'
keyboardType="email-address"
editable={true}
autoCapitalize = 'none'
value={textemailid}
theme={{ colors: { placeholder: "#f5f5f5", background: "transparent", text:
'green', primary: '#D43790' } }}
onChangeText={textemailid=>setTextEmailId(textemailid)}>
</TextInput>
</View>
<View style={styles.textinputpasswordview} >
<TextInput style={styles.textinputpassword}
underlineColor='grey'
label='Password'
autoCapitalize = 'none'
editable={true}
value={textpassword}
onChangeText={textpassword => setTextPassword(textpassword)}
theme={{ colors: { placeholder: "#f5f5f5", background: "transparent",text:
'green',primary: '#D43790' } }}>
</TextInput>
</View>
<View style={styles.loginbuttonview}>
{isLoading ? (
<ActivityIndicator size='small' color='green'/>
) :
(
<Button buttonStyle={{
backgroundColor: "#EB4207"
}}
containerStyle={{
marginTop: 12,
width: "50%"
}}
onPress={
() => { loginHandler();
}}
title='Log in'/>
)}
</View>
</View>
<TouchableOpacity style={styles.textforgotpasswordview} onPress=.
{()=>props.navigation.navigate('ForgotPasswordPage')}>
<Text style={styles.textforgotpassword}>Forgot your password?</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.textregisterview} onPress=.
{()=>props.navigation.navigate('SignUp')} >
<Text style={styles.textregister}>Not a member?Sign up now</Text>
</TouchableOpacity>
</View>
</ScrollView>
</KeyboardAvoidingView>
)}
const styles = StyleSheet.create({
container: {
backgroundColor: '#0B0B45',
flex:1,
},
subView: {
backgroundColor: '#1D1F33',
height: 750,
marginTop: 150,
borderTopRightRadius: 40,
borderTopLeftRadius: 40,
},
welcometextview:{
bottom:'80%',
justifyContent:'center',
alignItems:'center'
},
welcometext:{
fontWeight:'bold',
color:'grey',
fontSize:20,
},
textinputemailview:{
position:'absolute',
top:'23%',
width:'80%',
alignSelf:'center'
},
textinputemail:{
backgroundColor:'transparent',
fontWeight:'bold',
fontSize:20,
},
textinputpasswordview:{
position:'absolute',
top:'35%',
width:'80%',
alignSelf:"center"
},
textinputpassword:{
backgroundColor:'transparent',
fontWeight:'bold',
fontSize:20,
},
textregisterview:{
position:'absolute',
top:'75%',
alignSelf:'center'
},
textregister:{
color: "#EB4207",
fontSize: 20,
fontWeight: "bold",
textDecorationLine: 'underline'
},
textforgotpasswordview:{
position:'absolute',
alignSelf:'center',
bottom:'33%'
},
textforgotpassword:{
color: "white",
fontSize: 20,
fontWeight: "bold",
},
loginbuttonview:{
bottom:'45%',
justifyContent:'center',
alignItems:'center'
},
});
export default LoginScreen;
Below is the auth reducer:
auth.js:
import { GETDEVICEINFO, LOGIN,LOGOUT } from '../actions/auth';
const initialState = {
mobileno: null,
login_Status:null,
availableDevice:[],
};
export default (state = initialState,action) => {
switch(action.type){
case LOGIN:
return {
login_Status : action.loginStatus
};
case GETDEVICEINFO:
return {
availableDevice:action.devices
}
case LOGOUT:
return initialState;
default: return state;
}
}
I don't think async storage will work here because I don't want to persist data but only want to get data from auth store and also using AsyncStorage will not flush old data, it stores data till u logout and login.
After running the above code, I am getting the whole function as below:
login status is function login(textemailid, textpassword) {
var formData = new FormData();
formData.append('txtUemail', textemailid);
formData.append('txtUpass', textpassword);
return function _callee(dispatch) {
return _regenerator.default.async(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return _regenerator.default.awrap(fetch('https:--------
-/login.php', {
method: 'post',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: formData
}).then(function (res) {
return res.text();
}).then(function (loginresult) {
var login =
loginresult.replace('\r\n\r\n\r\n\t\r\n\t\r\n\t', '');
console.log('login1 is ' + login);
saveDataToStoragelogin(login, textemailid);
}).catch(function (err) {
console.log(err);
}));
case 2:
dispatch({
type: LOGIN,
loginStatus: login
});
case 3:
case "end":
return _context.stop();
}
}
}, null, null, null, Promise);
};
Can anyone say how to get only login_Status string. Thanks in Advance?
I would try to change
try{
props.navigation.navigate('LoginScreen', {
paramKey: login,
})
to
try{
navigation.navigate('LoginScreen', {
paramKey: login,
})
No need to pass navigation prop to auth store. When you dispatch({type:LOGIN}) with payload store that state in reducer.Get the State using UseSelector.
For example you are in Screen A and did login Api call and store api response data in reducer. In same screen use useSelector to get the api data response from reducer. based on response type navigate to respected screens. Don't place api call in reducers.
Please check this example https://github.com/raduungurean/react-native-redux-auth-login-logout-example

React Native, how to execute a component's method from App.js when using stack navigation

I finished a React Native course, and I'm trying to make a chat app to practice.
Summarize the problem:
I have 2 screens ,ContactList.js and ChatRoom.js
I have a Navigation stack with these two screens Navigation.js
The Navigation component is imported and rendered in App.js
I added FCM module to handle notifications
The goal is to execute the function that loads messages in the chatroom _loadMessages(), when the app receives a notification on foreground state. And to execute the function (I didn't create it yet) to update unread message in a global state.
What I've tried
I followed react native firebase docs, I have a function that handle notification on foreground declared inside App.js. The problem is that I can't tell the other components (the screens) to execute their functions. The "Ref" method can't be used cause I'm not calling the child component (the screens) directly inside the App.js, I'm calling and rendering the Navigation.js Stack instead.
So, in this case, when we have a navigation component called on app.js, how can we tell other components to execute a function that is declared inside them?
App.js
import React, { useEffect } from 'react'
import Navigation from './Navigation/Navigation'
import messaging from '#react-native-firebase/messaging';
export default function App() {
requestUserPermission = async () => {
//On récupere le token
const token = await messaging().getToken();
console.log('TOKEN: ' + token)
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Authorization status:', authStatus);
}
}
handleForegroundNotification = () => {
const unsubscribe = messaging().onMessage(async remoteMessage => {
console.log('A new FCM message arrived!', JSON.stringify(remoteMessage));
});
return unsubscribe;
}
useEffect(() => {
this.requestUserPermission();
this.handleForegroundNotification();
}, []);
return (
<Navigation />
)
}
Navigation.js
import { createAppContainer } from "react-navigation"
import { createStackNavigator } from "react-navigation-stack"
import ContactList from '../Components/ContactList'
import ChatRoom from '../Components/ChatRoom'
const ChatStackNavigator = createStackNavigator({
ContactList: {
screen: ContactList,
navigationOptions: {
title: 'Contacts'
}
},
ChatRoom: {
screen: ChatRoom,
navigationOptions: {
title: 'Conversation'
}
}
})
export default createAppContainer(ChatStackNavigator)
ChatRoom.js
import React from 'react'
import { View, StyleSheet, Text, Image, SafeAreaView, TextInput, Alert, FlatList, ActivityIndicator } from 'react-native'
import { sendMessage } from '../API/sendMessageApi'
import { getMessages } from '../API/getMessagesApi'
import MessageItem from './MessageItem'
class ChatRoom extends React.Component {
constructor(props) {
super(props)
this.message = ""
this.contact = this.props.navigation.getParam('contact')
this.state = {
defautInputValue: "",
listMessages: [],
isLoading: true
}
}
_textInputChanged(text) {
this.message = text
}
_sendMessage() {
this.setState({ defautInputValue: " " });
sendMessage('1', this.contact.id_contact, this.message).then(() => {
this._loadMessages();
});
}
_loadMessages() {
getMessages('1', this.contact.id_contact).then((data) => {
this.setState({ listMessages: data, isLoading: false, defautInputValue: "" })
});
}
componentDidMount() {
this._loadMessages();
}
_displayLoading() {
if (this.state.isLoading) {
return (
<View style={[styles.loading_container]}>
<ActivityIndicator size="large" color="orange" />
</View>
)
}
}
render() {
//console.log('Contact ID: ' + JSON.parse(this.contact))
return (
<SafeAreaView style={styles.container}>
<View style={styles.contact}>
<View style={styles.image_container}>
<Image
style={styles.image}
source={{ uri: 'https://moonchat.imedramdani.com/avatar/' + this.contact.avatar }}
></Image>
</View>
<View style={styles.username_container}>
<Text style={styles.username}>{this.contact.username}</Text>
</View>
</View>
{/* BODY */}
<View style={styles.body}>
<FlatList
ref={ref => this.flatList = ref}
onContentSizeChange={() => this.flatList.scrollToEnd({ animated: true })}
data={this.state.listMessages}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) =>
<MessageItem
message={item}
/>}
>
</FlatList>
</View>
<View style={styles.input_container}>
<TextInput
style={styles.input}
onChangeText={(text) => this._textInputChanged(text)}
onSubmitEditing={() => this._sendMessage()}
defaultValue={this.state.defautInputValue}
placeholder="Aa"
></TextInput>
</View>
{this._displayLoading()}
</SafeAreaView>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#1d2733',
},
contact: {
height: 50,
backgroundColor: '#1d2733',
marginTop: 0,
flexDirection: 'row',
borderBottomColor: 'grey',
borderWidth: 1
},
username_container: {
//backgroundColor: 'red',
flex: 3,
justifyContent: 'center',
alignItems: 'flex-start'
},
username: {
fontSize: 20,
color: 'white'
},
image_container: {
//backgroundColor: 'blue',
flex: 1,
justifyContent: 'center'
},
image: {
//backgroundColor: 'yellow',
height: 45,
width: 45,
marginLeft: 10,
borderRadius: 25
},
body: {
//backgroundColor: 'red',
flex: 1
},
input_container: {
height: 75,
//backgroundColor:'blue',
padding: 5
},
input: {
paddingLeft: 20,
height: 50,
backgroundColor: 'white',
borderWidth: 1,
borderRadius: 25,
borderColor: '#D5D5D5',
fontSize: 20
},
loading_container: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center'
},
});
export default ChatRoom
Thanks!
I set up a solution that worked, but I don't know if it is a proper way.
I restored App.js
import React from 'react'
import Root from './Root'
import { Provider } from 'react-redux'
import Store from './Store/configureStore'
class App extends React.Component {
render() {
return (
<Provider store={Store}>
<Root />
</Provider>
)
}
}
export default App
I created a now component Root.js which contains notification handler
import React from 'react'
import Navigation from './Navigation/Navigation'
import messaging from '#react-native-firebase/messaging'
import { connect } from 'react-redux'
class Root extends React.Component {
requestUserPermission = async () => {
//On récupere le token
const token = await messaging().getToken();
console.log('TOKEN: ' + token)
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Authorization status:', authStatus);
}
}
handleForegroundNotification = () => {
const unsubscribe = messaging().onMessage(async remoteMessage => {
console.log('A new FCM message arrived!', JSON.stringify(remoteMessage));
const action = { type: "RELOAD_MESSAGES", value: '1' }
this.props.dispatch(action)
});
return unsubscribe;
}
componentDidMount() {
this.requestUserPermission();
this.handleForegroundNotification();
}
render() {
return (
<Navigation />
)
}
}
const mapStateToProps = (state) => {
return {
loadyourself: state.loadyourself
}
}
export default connect(mapStateToProps)(Root)
The store is provided in App.js to let Root.js access the global state.
When a notification is received at foreground, the Root.js update a key in the global state named "loadyourself". When the state is updated, the ChatRoom.js which is connected to the store too, trigger the componentDidUpdate()
componentDidUpdate() {
if (this.props.loadyourself == "1") {
this._reloadMessages();
}
}
of course, to avoid the infinite loop, the _reloadMessages() restore default value in the global state of loadyourself key
_reloadMessages() {
const action = { type: "RELOAD_MESSAGES", value: '0' }
this.props.dispatch(action)
getMessages('1', this.contact.id_contact).then((data) => {
this.setState({ listMessages: data })
});
}
The messages are updated, the global state is re-initialized, the componentDidUpdate() does not trigger until next notification.
It works. Like I said, I don't know if there is a more proper way, I'm new in React-Native (2 weeks). I am open to other solutions

How to make a QR code scanner in React native using expo?

When I run https://snack.expo.io/#sushil62/qr-code-scanner in the expo which works fine, but when copy the same code given in App.js file, after running the application the camera opens but it shows no result while scanning, and
in expo also when changing the snack version 33 or higher it does not work there too.
import React, { Component } from 'react';
import { Alert, Linking, Dimensions, LayoutAnimation, Text, View, StatusBar, StyleSheet, TouchableOpacity } from 'react-native';
import { BarCodeScanner, Permissions } from 'expo';
export default class App extends Component {
state = {
hasCameraPermission: null,
lastScannedUrl: null,
};
componentDidMount() {
this._requestCameraPermission();
}
_requestCameraPermission = async () => {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({
hasCameraPermission: status === 'granted',
});
};
_handleBarCodeRead = result => {
if (result.data !== this.state.lastScannedUrl) {
LayoutAnimation.spring();
this.setState({ lastScannedUrl: result.data });
}
};
render() {
return (
<View style={styles.container}>
{this.state.hasCameraPermission === null
? <Text>Requesting for camera permission</Text>
: this.state.hasCameraPermission === false
? <Text style={{ color: '#fff' }}>
Camera permission is not granted
</Text>
: <BarCodeScanner
onBarCodeRead={this._handleBarCodeRead}
style={{
height: Dimensions.get('window').height,
width: Dimensions.get('window').width,
}}
/>}
{this._maybeRenderUrl()}
<StatusBar hidden />
</View>
);
}
_handlePressUrl = () => {
Alert.alert(
'Open this URL?',
this.state.lastScannedUrl,
[
{
text: 'Yes',
onPress: () => Linking.openURL(this.state.lastScannedUrl),
},
{ text: 'No', onPress: () => {} },
],
{ cancellable: false }
);
};
_handlePressCancel = () => {
this.setState({ lastScannedUrl: null });
};
_maybeRenderUrl = () => {
if (!this.state.lastScannedUrl) {
return;
}
return (
<View style={styles.bottomBar}>
<TouchableOpacity style={styles.url} onPress={this._handlePressUrl}>
<Text numberOfLines={1} style={styles.urlText}>
{this.state.lastScannedUrl}
</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.cancelButton}
onPress={this._handlePressCancel}>
<Text style={styles.cancelButtonText}>
Cancel
</Text>
</TouchableOpacity>
</View>
);
};
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#000',
},
bottomBar: {
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
backgroundColor: 'rgba(0,0,0,0.5)',
padding: 15,
flexDirection: 'row',
},
url: {
flex: 1,
},
urlText: {
color: '#fff',
fontSize: 20,
},
cancelButton: {
marginLeft: 10,
alignItems: 'center',
justifyContent: 'center',
},
cancelButtonText: {
color: 'rgba(255,255,255,0.8)',
fontSize: 18,
},
});
It would be very nice if someone suggests me to solve this or give me an example(such as downgrading the expo version) so that I can implement this.
You can use
expo-barcode-scanner
Run expo install expo-barcode-scanner
Usage
You must request permission to access the user's camera before attempting to get it. To do this, you will want to use the Permissions API. You can see this in practice in the following example.
import * as React from 'react';
import {
Text,
View,
StyleSheet,
Button
} from 'react-native';
import Constants from 'expo-constants';
import * as Permissions from 'expo-permissions';
import {
BarCodeScanner
} from 'expo-barcode-scanner';
export default class BarcodeScannerExample extends React.Component {
state = {
hasCameraPermission: null,
scanned: false,
};
async componentDidMount() {
this.getPermissionsAsync();
}
getPermissionsAsync = async() => {
const {
status
} = await Permissions.askAsync(Permissions.CAMERA);
this.setState({
hasCameraPermission: status === 'granted'
});
};
render() {
const {
hasCameraPermission,
scanned
} = this.state;
if (hasCameraPermission === null) {
return <Text > Requesting
for camera permission < /Text>;
}
if (hasCameraPermission === false) {
return <Text > No access to camera < /Text>;
}
return ( <
View style = {
{
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-end',
}
} >
<
BarCodeScanner onBarCodeScanned = {
scanned ? undefined : this.handleBarCodeScanned
}
style = {
StyleSheet.absoluteFillObject
}
/>
{
scanned && ( <
Button title = {
'Tap to Scan Again'
}
onPress = {
() => this.setState({
scanned: false
})
}
/>
)
} <
/View>
);
}
handleBarCodeScanned = ({
type,
data
}) => {
this.setState({
scanned: true
});
alert(`Bar code with type ${type} and data ${data} has been scanned!`);
};
}
Note: Passing undefined to the onBarCodeScanned prop will result in no scanning. This can be used to effectively "pause" the scanner so that it doesn't continually scan even after data has been retrieved.
Allow all the permisions which gets popped.
You're good to go!!
Hope this helps.

How to store username after logout and show it in TextInput on next login?

I have a login screen where I will enter a username and then after login I will go to home screen.
Now what I want is once the user comes out of the app and then open it again then it has to show the the username that has entered before.
How can I do this? I am using react-native-router-flux for navigation.
Here is my code:
import React, { Component } from 'react';
import {
StyleSheet,
Text,
TextInput,
Button,
View,
AsyncStorage
} from 'react-native';
import { Actions } from 'react-native-router-flux';
export default class AsyncStorageExample extends Component {
constructor(props) {
super(props);
this.state = {
myKey: null
};
}
async getKey() {
try {
const value = await AsyncStorage.getItem('#MySuperStore:key')
if (this.state.myKey === value) {
Actions.dashboard();
}
this.setState({ myKey: value });
} catch (error) {
console.log('Error retrieving data' + error);
}
}
async saveKey(value) {
try {
await AsyncStorage.setItem('#MySuperStore:key', value);
} catch (error) {
console.log('Error saving data' + error);
}
}
async resetKey() {
try {
await AsyncStorage.removeItem('#MySuperStore:key');
const value = await AsyncStorage.getItem('#MySuperStore:key');
this.setState({ myKey: value });
} catch (error) {
console.log('Error resetting data' + error);
}
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to Demo AsyncStorage!
</Text>
<TextInput
style={styles.formInput}
placeholder="Enter key you want to save!"
value={this.state.myKey}
onChangeText={(value) => this.saveKey(value)}
/>
<Button
style={styles.formButton}
onPress={this.getKey.bind(this)}
title="Get Key"
color="#2196f3"
accessibilityLabel="Get Key"
/>
<Button
style={styles.formButton}
onPress={this.resetKey.bind(this)}
title="Reset"
color="#f44336"
accessibilityLabel="Reset"
/>
<Text style={styles.instructions}>
Stored key is = {this.state.myKey}
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
padding: 30,
flex: 1,
alignItems: 'stretch',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
formInput: {
paddingLeft: 5,
height: 50,
borderWidth: 1,
borderColor: "#555555",
},
formButton: {
borderWidth: 1,
borderColor: "#555555",
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
marginTop: 5,
},
});
Using this I can get like this
When I enter some text then I will navigate to next screen; after that, if I come out of my app and open it again, then the previous value is not showing up in TextInput.
Where is it going wrong?
you can use AsyncStorage component of React Native. For more info AsyncStorage
You can set a value of user on logout.
AsyncStorage.setItem('UseName', 'name of user');
On login form get value from AsyncStorage in componentWillMount() method.
AsyncStorage.getItem('UserName')
.then((data) => {
if (data) {
this.setState({UserName:data}) //store data in state
}
}).done();

How to open the camera and taking the picture in react native?

I want to open the device camera from my app when user click on the button and when user click on back button it should react to my application from device camera. I am able to open camera and take photo by running react native project. But I want to do it how camera works in what's app. That is clicking on button -> opening camera -> send button .
I am an beginner in react native .I tried many ways but I am not getting how it can be done.
Can anybody assist me to do this.
My App.js code is,
'use strict';
import React, { Component } from 'react';
import {
AppRegistry,
Dimensions,
StyleSheet,
Text,
TouchableHighlight,
View
} from 'react-native';
import Camera from 'react-native-camera';
class BadInstagramCloneApp extends Component {
render() {
return (
<View style={styles.container}>
<Camera
ref={(cam) => {
this.camera = cam;
}}
style={styles.preview}
aspect={Camera.constants.Aspect.fill}>
<Text style={styles.capture} onPress={this.takePicture.bind(this)}>[CAPTURE]</Text>
</Camera>
</View>
);
}
takePicture() {
const options = {};
//options.location = ...
this.camera.capture({metadata: options})
.then((data) => console.log(data))
.catch(err => console.error(err));
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
},
preview: {
flex: 1,
justifyContent: 'flex-end',
alignItems: 'center'
},
capture: {
flex: 0,
backgroundColor: '#fff',
borderRadius: 5,
color: '#000',
padding: 10,
margin: 40
}
});
AppRegistry.registerComponent('BadInstagramCloneApp', () => BadInstagramCloneApp);
You can use the state to show/hide the camera view/component.
Please check the following code:
...
class BadInstagramCloneApp extends Component {
constructor(props) {
super(props);
this.state = {
isCameraVisiable: false
}
}
showCameraView = () => {
this.setState({ isCameraVisible: true });
}
render() {
const { isCameraVisible } = this.state;
return (
<View style={styles.container}>
{!isCameraVisible &&<Button title="Show me Camera" onPress={this.showCameraView} />}
{isCameraVisible &&
<Camera
ref={(cam) => {
this.camera = cam;
}}
style={styles.preview}
aspect={Camera.constants.Aspect.fill}>
<Text style={styles.capture} onPress={this.takePicture.bind(this)}>[CAPTURE]</Text>
</Camera>}
</View>
);
}
takePicture() {
const options = {};
//options.location = ...
this.camera.capture({metadata: options})
.then((data) => {
console.log(data);
this.setState({ isCameraVisible: false });
}
.catch(err => console.error(err));
}
}
...
You can use https://github.com/ivpusic/react-native-image-crop-picker for this. This component helps you to take photo and also the photo if required. Follow the documentation correctly and here is the code for camera selection option
ImagePicker.openCamera({
cropping: true,
width: 500,
height: 500,
cropperCircleOverlay: true,
compressImageMaxWidth: 640,
compressImageMaxHeight: 480,
freeStyleCropEnabled: true,
}).then(image => {
this.setState({imageModalVisible: false})
})
.catch(e => {
console.log(e), this.setState({imageModalVisible: false})
});
Correction of best answer because of deprecation of Camera to RNCamera plus missing closing bracket ")" right before the .catch and like a spelling mistake with the declaration of state:
But basically there's 2 routes, whether you're using expo or react native. You gotta have Pods/Ruby/Cocoapods or manually link and all that if you're using traditional React Native, but just go with expo-camera if you got an expo set up and don't listen to this.
This is a React-Native with Pods/Ruby/CocoaPods solution, whereas going with expo-camera might be much faster and better if you're not set up like this.
import React, { Component } from 'react';
import {
Text,
View,
StyleSheet,
Button,
TouchableOpacity
} from 'react-native';
import { RNCamera } from 'react-native-camera';
export default class Camera2 extends Component {
constructor(props) {
super(props);
this.state = {
isCameraVisible: false
}
}
showCameraView = () => {
this.setState({ isCameraVisible: true });
}
takePicture = async () => {
try {
const data = await this.camera.takePictureAsync();
console.log('Path to image: ' + data.uri);
} catch (err) {
// console.log('err: ', err);
}
};
render() {
const { isCameraVisible } = this.state;
return (
<View style={styles.container}>
{!isCameraVisible &&<Button title="Show me Camera" onPress={this.showCameraView} />}
{isCameraVisible &&
<RNCamera
ref={cam => {
this.camera = cam;
}}
style={styles.preview}
>
<View style={styles.captureContainer}>
<TouchableOpacity style={styles.capture} onPress={this.takePicture}>
<Text style={styles.capture} onPress={this.takePicture.bind(this)}>[CAPTURE]</Text>
<Text>Take Photo</Text>
</TouchableOpacity>
</View>
</RNCamera>}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
},
preview: {
flex: 1,
justifyContent: 'flex-end',
alignItems: 'center'
},
capture: {
flex: 0,
backgroundColor: '#fff',
borderRadius: 5,
color: '#000',
padding: 10,
margin: 40
}
});