Cannot read AsyncStorage value on React Native app startup - ios

I am using React Native with Redux. The following code is used to create the Redux store, and uses AsyncStorage to check if the user is logged in by checking the presence of an authToken.
import {createStore} from 'redux';
import {persistStore} from 'redux-persist';
async function getAuthToken() {
return await AsyncStorage.getItem('authToken');
}
export function createStore(onCompletion:() => void):any {
...
const store = createStore(
reducer,
{
auth: {
authenticated: !!getAuthToken()
}
},
enhancer);
persistStore(store, {
storage: AsyncStorage,
},
onCompletion);
}
The creation of the store:
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
store: createStore(...),
};
}
render() {
return (
<Provider store={this.state.store}>
<AppNavigator />
</Provider>
);
}
}
The authToken value get correctly set once the user logs in, and is removed once the user logs out. But the authToken does not get persisted after the app is relaunched. The first call to getAuthToken always returns this junk value from AsyncStorage:
{ _45: 0, _81: 0, _65: null, _54: null }
Why could this be happening?

Now you're returning a promise from AsyncStorage, you need to return the token value. Try:
async function getAuthToken() {
return await AsyncStorage.getItem('authToken').then((token) => token);
}

With hooks you useEffect
import AsyncStorage from '#react-native-async-storage/async-storage';
import { useState, useEffect } from 'react';
export function App() {
const [token, setToken] = useState<string>();
useEffect(()=>{
(async function() {
setToken(await AsyncStorage.getItem());
await SplashScreen.hideAsync();
})();
},[]);
if (token) {
return (<View><Text>{token}</Text></View>);
} else {
return null;
}
}

Related

react native google sign in - cannot press next, forgot email, or create account

image of simulator
unable to press the forgot email, create account or next button. When I press them there is no action, it stays on that same signin page. help, privacy and terms work.
wrote the function in the googlesignin.tsx file
import React, { Component } from 'react'
import { Button } from 'react-native'
import {
GoogleSignin,
statusCodes,
} from '#react-native-google-signin/google-signin';
export class GoogleSign extends Component {
constructor(props) {
super(props);
this.state = {
userInfo: null,
};
}
render() {
return(
<Button title={'Sign in with Google'} onPress={async () => {
GoogleSignin.configure({
iosClientId: '552669576534-ninopsfqvitpk59v9kt42mn0r2e4o37h.apps.googleusercontent.com',
webClientId: '552669576534-vpmbo9vbodnaeqghnjai6d0fhcl2enhc.apps.googleusercontent.com',
offlineAccess: true,
});
try {
await GoogleSignin.hasPlayServices();
const userInfo = await GoogleSignin.signIn();
this.setState({userInfo});
console.log(userInfo);
} catch (error) {
if (error.code === statusCodes.SIGN_IN_CANCELLED) {
// user cancelled the login flow
} else if (error.code === statusCodes.IN_PROGRESS) {
// operation (e.g. sign in) is in progress already
} else if (error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
// play services not available or outdated
} else {
// some other error happened
}
}
}}/>
);
}
}
I also have added my inverse url to the workspace.
Please refer this doc, you might have missed to configure signIn which is mandatory
import { GoogleSignin } from '#react-native-google-signin/google-signin';
GoogleSignin.configure();

Index error 404 when add swagger to Nestjs

My app is showing message look like "Server is running" at index url http://localhost:5001. But when i added swagger-ui for testing api document. I only able to access http://localhost:5001/api/docs. My index page return {"statusCode":404,"message":"Cannot GET /","error":"Not Found"}. when i try request by postman it works fine. Is there a way to display the original "server is running" message. Tks for your help!
open-api/index.ts:
import { INestApplication } from '#nestjs/common';
import { SwaggerModule, DocumentBuilder } from '#nestjs/swagger';
import {
SWAGGER_API_CURRENT_VERSION,
SWAGGER_API_DESCRIPTION,
SWAGGER_API_NAME,
SWAGGER_API_ROOT,
} from '../core/constants';
export const setupSwagger = (app: INestApplication) => {
const options = new DocumentBuilder()
.setTitle(SWAGGER_API_NAME)
.setDescription(SWAGGER_API_DESCRIPTION)
.setVersion(SWAGGER_API_CURRENT_VERSION)
.addBearerAuth()
.build();
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup(SWAGGER_API_ROOT, app, document);
};
open-api/index.ts:
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module';
import { ValidateAuthMiddleware } from './core/middlewares/validate-auth.middleware';
import { setupSwagger } from './open-api';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
setupSwagger(app);
app.useGlobalPipes(new ValidateAuthMiddleware());
await app.listen(5001);
}
bootstrap();

expo-location not working in ios and not showing location permission in app settings

I am trying to get current location in IOS 14, but i am getting no response and when i check in expo
settings it's not showing location permission there. I have checked in both simulator and physical device.
Hook Code
import { useEffect, useState } from "react";
import * as Location from "expo-location";
export default useLocation = () => {
const [location, setLocation] = useState();
const getLocation = async () => {
try {
const { granted } = await Location.requestPermissionsAsync();
if (!granted) return;
const {
coords: { latitude, longitude },
} = await Location.getLastKnownPositionAsync();
setLocation({ latitude, longitude });
} catch (error) {
console.log(error);
}
};
useEffect(() => {
getLocation();
}, []);
return location;
};
Response
undefined
The docs says Location.getLastKnownPositionAsync() might return null:
Returns a promise resolving to an object of type LocationObject or
null if it's not available or doesn't match given requirements such as
maximum age or required accuracy.
so you should do something like:
import { useEffect, useState } from "react";
import * as Location from "expo-location";
export default useLocation = () => {
const [location, setLocation] = useState();
const getLocation = async () => {
try {
const { granted } = await Location.requestPermissionsAsync();
if (!granted) return;
const last = await Location.getLastKnownPositionAsync();
if (last) setLocation(last);
else {
const current = await Location.getCurrentPositionAsync();
setLocation(current);
}
} catch (error) {
console.log(error);
}
};
useEffect(() => {
getLocation();
}, []);
return location;
};
use requestForegroundPermissionAsync() instead of requestPermissionAsync. and the problem is solved.

How to trigger state update with react-navigation?

In my React Native application I'm trying to change state and trigger a re-render of a component. It should be done when NavBottom calls this.props.navigation.navigate('captureView') to navigate to CaptureView. The state update should reset the CaptureView photo state variable back to its original value.
How can state be changed in React Native with react-navigation on navigate? https://reactnavigation.org/docs/en/navigation-actions.html
CaptureView is part of CaptureStack
import { createStackNavigator } from "react-navigation";
const CaptureStack = createStackNavigator({
captureView: CaptureView,
detailView: DetailView,
reportView: ReportView,
});
const Tab = createBottomTabNavigator({
capture: CaptureStack,
}, {
initialRouteName: 'capture',
tabBarComponent: NavBottom
});
CaptureView.js:
import { StackActions, NavigationActions, NavigationEvents } from 'react-navigation';
class CaptureView extends Component {
static navigationOptions = {}
constructor(props) {
super(props);
console.log("CaptureView: constructor(props)");
}
componentDidMount() { // called just once
console.log("CaptureView: componentDidMount()");
// this.setState = { // undefined???
// photo: null // this needs to be RESET
// };
}
componentWillUnmount() {
console.log("CaptureView: componentWillUnmount()");
}
async onButtonPress() {
CameraService.takePicture().then((photo)=>{
this.setState({
photo: photo
});
// More actions
this.props.navigation.navigate(
"detailView",
{
id: 'DetailView',
photo
}
);
});
}
render() {
return (
<Camera
cameraSetter={(cam) => {
CameraService.setCamera(cam)
}}
photo={this.state.photo}
/>
<TouchableOpacity onPress={this.onButtonPress.bind(this)}>
<Text>TAKE PHOTO</Text>
</TouchableOpacity>
);
}
}
Then in other part of the application there is a button to navigate back to CaptureView.
NavBottom.js:
export default class NavBottom extends Component {
constructor(props) {
super(props);
}
render() {
return (
<View>
<TouchableOpacity onPress={() => this.props.navigation.navigate('captureView')}>
<Text>CAMERA</Text>
</TouchableOpacity>
</View >);
}
}
Notes
I've tried different ways from ReactJS (not React Native) documentation that failed:
https://reactjs.org/docs/react-component.html#componentdidmount - componentDidMount() seems to bee the recommended way in documentation, but in my application it gets called ONLY ONCE?
Even when componentDidMount() is called once at the beginning, but even then this.setState() is undefined. It's strange, the documentation says it should be available
have you tried using navigation events to reset the state of your CaptureView component?
I think onWillFocus might do the trick.
https://reactnavigation.org/docs/en/navigation-events.html
React Navigation doesn't re-render a component in a stack that resides in Tab Naviagtor
in order perform forceful re-render than you can use event listener like this
componentDidMount() {
this._navListener = this.props.navigation.addListener('didFocus', () => {
//perform any action you want, place your logic here
});
}
you can also use React Navigation's HOC withNavigation this pass a ( isFocused ) prop to the connected component
componentDidUpdate(prevProps, prevState) {
if(prevProps.isFocused !== this.props.isFocused){
//place your desired logic here
}
}
Usage of withNavigation
import { withNavigationFocus } from 'react-navigation';
...
...
...
export default withNavigationFocus(YourComponent)

React mobx does not inject stores properly

I have implemented this but the store has no values (all undefined):
This is the store:
export default class AppState {
// Is authenticated
#observable authenticated;
#action get authenticated() {
return this.authenticated;
}
doSomethingWithNoDecorator() {
return this.authenticated;
}
}
This is index.js:
const stores = {
AppState
};
const renderApp = Component => {
render(
<AppContainer>
<Provider { ...stores }>
<Router>
// Routes
</Router>
</Provider>
</AppContainer>,
document.getElementById("root")
);
};
This is the Component:
#inject("AppState")
#observer
export default class SidebarListItem extends Component {
constructor(props) {
super(props)
this.store = this.props.AppState;
}
doSomething() {
this.store.authenticated();
this.store.doSomethingWithNoDecorator();
this.store.authenticated;
}
}
The store is not null... I can see the function. But I can't get any field or invoke any method.
What did I do wrong?
Regards,
Idob
You need to initialise your store:
const stores = { AppState: new AppState() }
By the way, #actions cannot be applied to getters.

Resources