React-Native AsyncStorage - javascript

I didn't understand how to make the AsyncStorage work.
I use react-native-router-flux
Basically I have 3 pages:
FirstPage
export default class Authentication extends Component {
render() {
return (
..........
<TouchableOpacity
style ={[style.button, style.buttonOK]}
onPress={() => Actions.login() }>
<Text style={style.buttonTesto}>LOGIN</Text>
</TouchableOpacity>
<TouchableOpacity
style ={[style.button, style.buttonOK]}
onPress={() => Actions.signup() }>
<Text style={style.buttonTesto}>SIGNUP</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
Login
login() {
let ctrl = true;
......
if (ctrl) {
let formdata = new FormData();
const identity = {
AppName: {
Username: this.state.username,
Password: this.state.password
}
};
formdata.append("Identity", JSON.stringify(identity));
fetch(APILINK , {
method: "POST",
headers: {
"Content-Type": "multipart/form-data"
},
body: formdata
})
.then(response => response.json())
.then(responseData => {
if (responseData.Error) {
.......
} else {
global.utente = new Utente(responseData);
Actions.homepageutente();
}
})
.catch(err => alert("err:" + err));
}
}
Utente
export default class Utente {
constructor(data) {
Utente.saveUtenteLoggato(data);
this._data = data;
....
);
}
get data() {
return this._data;
}
//there is a function for the signup there//
.......
static async saveUtenteLoggato(value) {
try {
await AsyncStorage.setItem("#UtenteLoggato", JSON.stringify(value));
} catch (error) {
console.log(error.message);
}
}
static async getUtenteLoggato() {
try {
return await AsyncStorage.getItem("#UtenteLoggato");
} catch (error) {
console.log(error.message);
return null;
}
}
static async clearUtenteLoggato() {
try {
global.utente = null;
await AsyncStorage.removeItem("#UtenteLoggato");
} catch (error) {
console.log(error.message);
return null;
}
}
}
So in Utente I have created the Asyncstorage function, but I don't understand how I should do when I close the app in backgroun (for example) to maintain the login active. At the moment if I go back in the App I should do another time the Login.
How can I solve it?
EDIT
Starting page
class Starting extends Component {
constructor(props)
{
super(props)
this.state = {
loading: true
}
}
componentWillMount() {
Utente.getUtenteLoggato()
.then(dataUtenteLoggato => {
if (dataUtenteLoggato !== null) {
global.utente = new Utente(JSON.parse(dataUtenteLoggato));
} else {
Actions.authentication();
}
})
.catch(err => {
console.log(err);
})
.finally(() => {
this.setState({ loading: false });
});
}
render() {
return(
<View style={style.container}>
<Spinner visible={this.state.loading} textContent={"Loading..."} textStyle={{color: '#FFF'}} />
</View>
);
}
}

You can implement splash screen component and check auth in componentWillMount. As example - get data from AsyncStorage, then perform request to check that user is authenticated and fetch user details. If auth data(e.g. auth token) is absent in storage or server threw auth error(in case when token is invalid or expired), redirect user to login screen, else mark user as authenticated and show main screen.

Related

Nodejs react cannot get data on frontend

I'm trying to get all user data from the backend to display on the webpage. However, the getAllUsers() seems to not send back a response as the console.logs are not printed out.
Here is my ViewUsers.js
import React, { Component } from "react";
import AdminServices from "../Services/AdminServices";
import "././ViewUsers.css"
const ViewUsersComponent = (users) => {
return (
<div className="viewusers">
<h1>All users</h1>
<div className="viewusers-list">
{users.map((user) => {
return (
<React.Fragment>
<p> <b>Name</b> : {user.username} </p>
<p> <b>Email</b> : {user.email} </p>
<p> <b>Website role</b> : {user.websiteRole} </p>
<hr />
</React.Fragment>
)
})}
</div>
</div>
)
}
export default class ViewUsers extends Component {
constructor(props) {
super(props);
this.retrieveUsers = this.retrieveUsers.bind(this);
this.state = {
users: []
}
}
componentDidMount() {
this.retrieveUsers();
}
retrieveUsers() {
AdminServices.getAllUsers()
.then(response => {
if (response && response.data) {
this.setState({
users: response.data
});
}
console.log(response.data);
console.log('DATA RECEIVED')
})
.catch(e => {
console.log('ERROR')
console.log(e);
});
}
render () {
const { users } = this.state;
console.log(users)
if (Array.isArray(users) && users.length) {
return ViewUsersComponent(users)
} else {
return (
window.location = '/notfound'
)
}
}
}
This is the AdminServices.js
import http from "../http-common"
class AdminServices {
getAllUsers() {
return http.get("/users");
}
getAllProjects() {
return http.get("/projects");
}
}
export default new AdminServices();
And the http-common.js
import axios from "axios";
export default axios.create({
baseURL: "http://localhost:8080",
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
},
mode: "cors",
credentials: "include",
withCredentials: true
});
And the userRoute.js
const express = require('express');
const User = require('../models/user').userModel;
const userRouter = express.Router();
// get all users
userRouter.get('/', async (req, res) => {
try {
console.log("loading users")
users = await User.find();
if (users == null) {
res.status(404).json({ message: "users not found" });
}
res.send(users);
} catch (err) {
res.status(500).json({ message: err.message });
}
});
When I send a get request to the user route via rest api, it works so I am not sure why it does not go through on the frontend
Please add CORS on backend project. You can configure the UI domain or use ‘*’ to allow all domain.

Why is props un changed by map state to props in React Redux

I have updated my store by using mapDispatchToProps like so:
function mapDispatchToProps(dispatch){
return{
addFirstImageUrl: (firstUrl) => dispatch({
type: "ADD_FIRST_IMAGE_URL",
firstUrl
})
}
}
I know that this works because when I run mapStateToProps I log the state like so:
function mapStateToProps(state){
console.log(state)
return{
firstImageUrl: state.firstImageUrl
}
}
This returns:
}
Object {
"posts": Object {
"firstImageTitle": "",
"firstImageUrl": "https://firebasestorage.MYURL",
"secondImageTitle": "",
"secondImageUrl": "",
},
}
however when I call this.props.firstImageUrl it returns undefined. I feel like this should return the url above, is this thinking wrong?
component function:
uploadImage = async (uri) => {
const response = await fetch(uri);
const blob = await response.blob();
var ref = firebase
.storage()
.ref()
.child(new Date().toString());
const snapshot = await ref.put(blob)
const url = await snapshot.ref.getDownloadURL();
this.props.addFirstImageUrl(url);
console.log("First Image Url: " + this.props.firstImageUrl)
};
import React from "react";
import {
StyleSheet,
Text,
View,
TouchableOpacity
} from "react-native";
import { Camera } from "expo-camera";
import * as Permissions from "expo-permissions";
import { FontAwesome } from "#expo/vector-icons";
import * as firebase from "firebase";
import { connect } from "react-redux";
import { addFirstImageUrl } from "../store/actions/posts";
import { bindActionCreators } from "redux";
function mapStateToProps(state){
console.log(state)
return{
firstImageUrl: state.firstImageUrl
}
}
function mapDispatchToProps(dispatch){
return{
addFirstImageUrl: (firstUrl) => dispatch({
type: "ADD_FIRST_IMAGE_URL",
firstUrl
})
}
}
class FirstCameraScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
hasCameraPermissions: null,
type: Camera.Constants.Type.back,
isFlashLIghtOn: Camera.Constants.FlashMode.off,
firstImageUrl: " "
};
}
static navigationOptions = {
title: "FirstCamera"
};
//ask for camera permission
async componentDidMount() {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({
hasCameraPermissions: status === "granted"
});
}
// Flip the camera
flipCamera = () => {
this.setState({
type:
this.state.type === Camera.Constants.Type.back
? Camera.Constants.Type.front
: Camera.Constants.Type.back
});
};
//Toggle Flashlight
flashLight = () => {
this.setState({
isFlashLIghtOn:
this.state.isFlashLIghtOn === Camera.Constants.FlashMode.off
? Camera.Constants.FlashMode.on
: Camera.Constants.FlashMode.off
});
};
//Take Picture and send to home
takePicture = async () => {
if (this.camera) {
let photo = await this.camera.takePictureAsync();
if (!photo.cancelled) {
await this.uploadImage(photo.uri);
}
this.props.navigation.navigate("FirstNamingScreen");
}
};
uploadImage = async (uri) => {
const response = await fetch(uri);
const blob = await response.blob();
var ref = firebase
.storage()
.ref()
.child(new Date().toString());
const snapshot = await ref.put(blob)
const url = await snapshot.ref.getDownloadURL();
this.props.addFirstImageUrl(url);
console.log("First Image Url: " + props.posts)
};
render() {
const { hasCameraPermissions } = this.state;
const { navigate } = this.props.navigation;
if (hasCameraPermissions === null) {
return <View />;
} else if (hasCameraPermissions === false) {
return (
<View>
<Text>No access to Camera</Text>
</View>
);
} else if (hasCameraPermissions === true) {
return (
<View style={styles.container}>
<Camera
style={styles.cameraView}
type={this.state.type}
flashMode={this.state.isFlashLIghtOn}
ref={ref => {
this.camera = ref;
}}
>
<View style={styles.actionContainer}>
<TouchableOpacity
onPress={() => this.flipCamera()}
style={styles.iconHolder}
>
<FontAwesome name="camera" size={35} style={styles.icon} />
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
this.takePicture();
}}
style={styles.iconHolder}
>
<FontAwesome name="circle" size={35} style={styles.icon} />
</TouchableOpacity>
<TouchableOpacity
onPress={() => this.flashLight()}
style={styles.iconHolder}
>
<FontAwesome name="flash" size={35} style={styles.icon} />
</TouchableOpacity>
</View>
</Camera>
</View>
);
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(FirstCameraScreen)
Change the mapStateToProps to this.
function mapStateToProps(state) {
console.log(state);
return {
firstImageUrl: state.posts.firstImageUrl
};
}
And your uploadImage method.
uploadImage() {
const response = await fetch(uri);
const blob = await response.blob();
var ref = firebase
.storage()
.ref()
.child(new Date().toString());
const snapshot = await ref.put(blob);
const url = await snapshot.ref.getDownloadURL();
this.props.addFirstImageUrl(url);
console.log("First Image Url: " + this.props.firstImageUrl);
};
constructor
constructor(props) {
super(props);
this.uploadImage = this.uploadImage.bind(this);
this.state = {
hasCameraPermissions: null,
type: Camera.Constants.Type.back,
isFlashLIghtOn: Camera.Constants.FlashMode.off,
firstImageUrl: " "
};
}

React Native post request causes infinite loop when displaying array

I am navigating to this 'History' tab from a side menu in React Native Navigation. Got a username for which I get all the 'bookings' made, but I can see in the warning tab that there are countless requests being made even after the component has been mounted, so there's an infinite loop probably caused by setState. Where should I call getHistory(), as in to make only one request, unless of course the component is reloaded. Thank you!
constructor(props){
super(props);
this.state = {
loggedUser: 'none',
bookingsInfo: []
}
}
getData = async () => {
try {
const value = await AsyncStorage.getItem('loggedUser')
if(value !== null) {
this.setState({
loggedUser: value
})
}
} catch(e) {
console.error(e);
}
}
getHistory() {
fetch('https://porsche.e-twow.uk/reactnative/istoric.php', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Cache-Control': 'no-cache, no-store'
},
body: JSON.stringify({
username: this.state.loggedUser
})
})
.then((response) => response.json())
.then((data) => {
this.setState({
bookingsInfo: data
});
})
.catch((error) => {
console.error(error);
});
}
componentDidMount() {
this.getData();
}
render() {
this.getHistory();
return (
<View style={styles.view}>
<ScrollView style={styles.scrollView}>
{
this.getHistory()
}
{
this.state.bookingsInfo ? this.state.bookingsInfo.map((item, index) => {
return (
<View style={styles.mainButton} key={item.id_scooter}>
<Text style={styles.mainButtonText}>Scooter-ul {item.id_scooter}</Text>
<Text style={styles.mainButtonText}>Data start: {item.start}</Text>
<Text style={styles.mainButtonText}>Data final: {item.end}</Text>
</View>
)
}) : null
}
</ScrollView>
<Footer/>
</View>
);
}
}
you are setting state in render.Calling setState here makes your component a contender for producing infinite loops.
place getHistory in componentDidMount .
componentDidMount() {
this.getHistory();
}

React native facebook login recevied user name pass to set profile screen

I'm using react native with expo and I received user name via facebook login code is here :
export default class FacebookLogin extends Component {
constructor(props) {
super(props);
this.state = { userInfo: null };
}
_handleFacebookLogin = async () => {
try {
const { type, token } = await Facebook.logInWithReadPermissionsAsync(
'my own app is not a problem',
{ permissions: ['public_profile'] }
);
switch (type) {
case 'success': {
const response = await fetch(
`https://graph.facebook.com/me?access_token=${token}`
);
const userInfo = await response.json();
this.setState({ userInfo });
Alert.alert('Logged in!', `Hi ${userInfo.name}`);
this.props.facebookloginpress();
break;
}
case 'cancel': {
Alert.alert('Cancelled!', 'Login was cancelled!');
break;
}
default: {
Alert.alert('Oops!', 'Login failed!');
}
}
} catch (e) {
Alert.alert('Oops!', 'Login failed!');
}
};
render() {
return (
<View style={styles.container}>
<Button
title="Login with Facebook"
onPress={this._handleFacebookLogin}
/>
</View>
);
}
}
it is okay not a problem but I want to pass userInfo.name to my Profile screen and to print as a text on my profile screen, profil screen code is here:
export default class Profile extends React.Component {
constructor(props) {
super(props);
}
handleSignOutPress = () => {
this.props.navigation.navigate('LoginScreen');
};
render() {
return (
<View style={{ flex: 1, justifyContent: 'space-around' }}>
<Text>This text take a facebook username</Text>
<Button
backgroundColor="#03A9F4"
title="SIGN OUT"
onPress={this.handleSignOutPress}
/>
</View>
);
}
}
// thanks for your help

React Native Redux how can I update UI, navigate to new screen after call API that without used flag

I'm developing a mobile application by use react-native and redux,thunk and it's the first time I write by react-native.
My problem is I call an api and the response is valid, I want to do somethings as update UI, navigate to new screen... for do that I will need to used flag in my component to mark it.
This is login example, after user login success, i want to navigate to Home screen. for do that, i need check an flag isLoginSuccess in props on the method componentWillReceiveProps to know user have been login success or not, but i think it's not good solution.
My question is we have other way to do it without use flag.
action.js
export const LOGIN_SUCCESS = "LOGIN_SUCCESS";
export const LOGIN_FAIL = "LOGIN_FAIL";
export const LOGIN = "LOGIN";
export function login(username, password) {
console.log(username)
return {
type: LOGIN,
username: username,
password: password
}
}
export function loginSuccess(data) {
return {
type: LOGIN_SUCCESS,
loginData: data
}
}
export function loginFail(error) {
return {
type: LOGIN_FAIL,
error: error
}
}
export function doLogin(username, password) {
return (dispatch) => {
dispatch(login(username, password))
api.login(username, password)
.then(response => response.json())
.then(jsonData => {
console.log(jsonData)
dispatch(loginSuccess(jsonData))
})
.catch((error) => {
dispatch(loginFail(error))
})
}
}
reducer.js
const initialState = {
loginData:{},
isLoginDoing : false,
isLoginSuccess : false,
username :"",
password : "",
error : {},
}
export default function(state = initialState , action ={}){
switch(action.type){
case actionType.LOGIN:{
return {
...state,
username: action.username,
password: action.password,
isLoginDoing : true
}
}
case actionType.LOGIN_SUCCESS:{
return {
...state,
loginData: action.loginData,
isLoginDoing : false,
isLoginSuccess : true
}
}
case actionType.LOGIN_FAIL:{
return {
...state,
isLoginDoing : false,
isLoginSuccess : false,
error : action.error
}
}
default :{
return state
}
}
}
component.js
import { connect } from "react-redux"
import { bindActionCreators } from 'redux';
import { doLogin } from '../actions'
import BaseComponent from './baseComponent'
class Login extends BaseComponent {
constructor(props) {
super(props)
this.state = {
username: '',
password: '',
}
this.functionLogin = this.functionLogin.bind(this);
}
functionLogin() {
const { username, password } = this.state;
if(!this.props.loginReducer.isLoginDoing){
this.props.doLogin(username, password)
}
}
componentWillReceiveProps (nextProps) {
console.log("componentWillReceiveProps");
const { navigate, goBack } = this.props.navigation;
if(nextProps.loginReducer.isLoginSuccess){
// this._navigateTo('Home')
navigate('Home',nextProps.loginReducer.loginData);
}
}
render() {
const { navigate, goBack } = this.props.navigation;
return (
<View style={{ backgroundColor: 'color', marginTop: 10 }} >
<TextInput
style={{ height: 40 }}
placeholder="Username"
onChangeText={value => this.setState({ username: value })}
/>
<TextInput
style={{ height: 40 }}
placeholder="Password"
onChangeText={value => this.setState({ password: value })}
/>
<Button
onPress={this.functionLogin}
title="Login"
color="#841584"
/>
</View>
);
}
}
const mapStateToProps = (state) => {
console.log(state);
return {
loginReducer: state.loginReducer
};
}
function mapDispatchToProps(dispatch) {
return {
doLogin: (username, password) => dispatch(doLogin(username, password))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Login)
Thanks
In your function doLogin, you can dispatch a navigation action after dispatch(loginSuccess(jsonData)).
For example for react-navigation (if you have integrated it with redux, if it's not the case, see https://reactnavigation.org/docs/guides/redux):
dispatch(NavigationActions.navigate({routeName: 'Home'});
(Don't forget import { NavigationActions } from 'react-navigation';)

Categories