I am using AsyncStorage to keep user data to phone. After registering the user, i am trying to retrieve the user if exist one and automate redirect to profile page.
but I have problems with async storage because it returns only the word 'user' in the console...
in the login component ->
import AsyncStorage from '#react-native-async-storage/async-storage';
const loggedUser = async () => {
try {
const u = await AsyncStorage.getItem('user');
console.log(u);
} catch (error) {
console.log(error);
}
};
/**
*
* This function retrieve the data from the server and store it to the local database..
*
*/
const executeLogin = async (email, password) => {
try
{
// Get data and store in async storage
const response = await data.post('/api/login', {email, password});
storeData('user', response.data); -> //Check the code bellow for the source
}
// Catch all errors bellow
catch (error)
{
if (error.response.status === 404 && error.response.data === 'Wrong credentials') {
Alert.alert('Whoops!', 'You entered the wrong credentials. Please try again.');
}
else {
Alert.alert('Whoops!', 'Something went wrong. This is an unexpecred error. We will try to fix it as soon as possible');
}
}
};
export default executeLogin;
The code block above calls the axios and supose to store the data to async storage. But I have no ideea also if it worked because it gave me no error...
import AsyncStorage from '#react-native-async-storage/async-storage';
/**
*
* This function must only accept serialised object with JSON.stringfy() method
*
*/
const storeData = async object => {
try
{
await AsyncStorage.setItem('user', object);
}
catch (error)
{
console.log(error);
}
}
export default storeData;
This is the store function
Cannot understand what I am doing wrong....
Thanks, Daniel
Related
Everytime when I run the app, I get a warning about the AsyncStorage. But the warning previously was just saying install something else to replace it and thats all. But now the warning is saying it will be removed in future released. So I had no choice to install it by following: https://react-native-async-storage.github.io/async-storage/docs/install
Installing : npm install #react-native-async-storage/async-storage
According to the usage from the link above, AsyncStorage is now added after await
Example from the usage:
const storeData = async (value) => {
try {
await AsyncStorage.setItem('#storage_Key', value)
} catch (e) {
// saving error
}
}
Which I tried to add to the await codes I have for my authentication with firebase.
Original Login:
const handleLogin = async () => {
try {
if (email && password) {
const { user } = await signInWithEmailAndPassword(auth, email, password)
console.log('Logged in as :' , user.email);
}
} catch (error) {
console.log({error});
setShowError(true);
}
}
Edited login for the await line and also importing:
import AsyncStorage from '#react-native-async-storage/async-storage';
const { user } = await AsyncStorage.signInWithEmailAndPassword(auth, email, password)
After editing, my login did not work anymore. I get the error of {"error": [TypeError: _asyncStorage.default.signInWithEmailAndPassword is not a function. (In '_asyncStorage.default.signInWithEmailAndPassword(_firebase.auth, email, password)', '_asyncStorage.default.signInWithEmailAndPassword' is undefined)]} How do I do to correct this? As I have 2 more function that uses await
Under my register screen, i also have the line that uses await:
const handleSignUp = async () => {
try {
if (email && password) {
setShowError(false);
const { user } = await createUserWithEmailAndPassword(auth, email, password)
console.log('Registered as :' , user.email);
try{
await signOut(auth)
console.log("Signed out successfully")
navigation.replace("Login")
}catch (error) {
console.log({error});
}
}
} catch (error) {
console.log({error});
setShowError(true);
}
}
Under my app.js, i also has that line for logout:
const handleSignOut = async () => {
try {
await signOut(auth);
console.log("Signed out successfully");
RootNavigation.navigate('Login');
} catch (error) {
console.log({ error });
}
}
My bad on not linking it to firebase. This is indeed firebase code that is run with expo. I am using firebase authentication with expo thus having this issue. Is there anyway to implement this AsyncStorage with firebase? Or do I not have to worry about this even though the old version is going to be removed?
Im making a user authorization process with JWT tokens.
How does the flow look like?
User logs in - gets an access token and a refresh token from a server, as a response
Access token comes in json body and is saved in local storage. Refresh token comes in a httpOnly cookie.
User can use getAllUsers method untill access token is valid.
Whenever getAllUsers method returns 401 unauthorized (when access token expires), there is a request being sent to refresh token endpoint - getRefreshToken, which returns new access token that is being saved to local storage
Refresh token expires and user is being logged out.
Whole flow in Postman works but i have got problem at frontend side.
Function getAllUsers works until access token expires.
Thats why I made a global function in a util file that checks if a response is 401 and if so, it sends a request to get a new access token and calls a function which returned that error.
However it does not work.
I think that the problem is in getAllUsers function which immediately goes to catch block (when cant fetch list of users because of 401) and does not invoke that global function from util file. Console logs from both functions (getDataFromResponse, getRefreshToken) does not work so it does not even get there.
Any ideas??
API utils file
import { AxiosResponse } from "axios";
import { apiService } from "./api.service";
type ApiServiceMethods = keyof typeof apiService;
export const getDataFromResponse = async (
response: AxiosResponse,
funName: ApiServiceMethods,
...args: any
): Promise<any> => {
if (response.status === 401) {
console.log("error");
await apiService.getRefreshToken();
return await apiService[funName](args);
}
return response.data;
};
API Service:
import { getDataFromResponse } from "./api.utils";
import axios from "./axios";
type LoginArgs = {
password: string;
username: string;
};
const apiServiceDef = () => {
const login = async (args: LoginArgs) => {
try {
const response = await axios.post("/login", {
username: args.username,
password: args.password,
});
const { data } = response;
const { token } = data;
localStorage.setItem("accessToken", token);
return response;
} catch (e) {
throw new Error("Custom");
}
};
/* problem here */
const getAllUsers = async () => {
const Token = localStorage.getItem("accessToken");
try {
const response = await axios.get("/users", {
headers: {
Token,
},
});
return await getDataFromResponse(response, "getAllUsers");
} catch (e) {
console.log(e);
}
};
/* problem here */
const getRefreshToken = async () => {
try {
console.log("fetch new access token");
const response = await axios.get("/refreshToken");
if (response.status === 401) {
localStorage.removeItem("accessToken");
throw new Error("TokenExpiredError");
}
const { data } = response;
const { token } = data
localStorage.setItem("accessToken", token);
return response;
} catch (e) {
console.log(e);
}
};
return { login, getRefreshToken, getAllUsers };
};
export const apiService = apiServiceDef();
I usually use a wrapper around the async functions or just use axios interceptors (https://stackoverflow.com/a/47216863/11787903). Be sure that err.response.status is right property, not sure about that, but this solution should work for you.
const asyncWrapper = async (handler) => {
try {
return handler()
} catch (err) {
if (err.response.status === 401) {
// refresh token then again call handler
await refreshToken()
return handler()
}
}
}
const getAllUsers = asyncWrapper(() => {
const Token = localStorage.getItem("accessToken");
return axios.get("/users", {
headers: {
Token,
},
});
});
i have one project in spring boot where i have created one API login.where i am sending user name and password with this API .if data is present in database it is returning login successfully if not then it is returning login fail.in react i have to text filed and i am storing that data.now i want to call login API in react with saved text field value and if login successfully then i want to save that response or that returned value in react it may be login successfully or all user details or show that response in react.please anyone help
Use Error handling function
try{
//Call your API here
}
catch(){
//Error handles here
}
finally{
//Executes anyway
}
You have to save your response in state then show it on frontend
import axios from 'axios';
const [loginData, setLoginData] = useState([]);
const onSubmit = async (e) => {
e.preventDefault();
try {
const requestBody = {
emailAddress: email,
password: password,
}
axios.post(`${config.url.API_URL}${BASE_URL.Auth_BASE_URL}/login`, requestBody)
.then(response => {
if (response) {
setLoginData(response);
console.log("Login success");
} else {
console.error("Login fail");
}
}).catch(function (error) {
console.log(error);
});
} catch (err) {
console.log(err);
}
}
I am implementing firebase authentication to Nuxt js application and I am so close. The problem is I want to commit a vuext mutation inside firebase's default function onAuthStateChanged(). But when ever I load the page it shows the following error:
"Uncaught (in promise) TypeError: Cannot read properties of undefined (reading '$store')"
Can you guys please help me out with this problem.
Thanks.
import firebase from '#/plugins/firebase'
import {
getAuth,
signInWithEmailAndPassword,
onAuthStateChanged
} from "firebase/auth"
export const state = () => ({
user: null,
authIsReady: false
})
export const mutations = {
updateUser(state, payload) {
state.user = payload
console.log('user is updated', state.user)
},
setAuthIsReady(state, payload) {
state.authIsReady = payload
console.log(state.authIsReady)
}
}
export const actions = {
async signIn(context, {
email,
password
}) {
console.log('sign in action')
const res = await signInWithEmailAndPassword(getAuth(), email, password)
if (res) {
context.commit('updateUser', res.user)
} else {
throw new Error('could not complete sign in')
}
}
}
// this function is causing the problem
const unsub = onAuthStateChanged(getAuth(), (user) => {
this.$store.commit('updateUser', user)
unsub()
})
The firebase.js file that I'm importing "auth" from below, is just all the regular setting up Firebase in Nuxt stuff... and the important lines are:
const auth = getAuth()
export { auth }
Try the code below ... I have mine in a file named "fireauth.js" in the plugins folder (don't forget to import the "fireauth.js" file in your nuxt.config.js)
import {
auth
} from "~/plugins/firebase.js";
export default (context) => {
const {
store
} = context
return new Promise((resolve, reject) => {
auth.onAuthStateChanged((user) => {
if (user) {
return resolve(store.dispatch('onAuthStateChangedAction', user))
}
return resolve()
})
})
}
In your store/index.js file add the following async function in your actions setting:
async onAuthStateChangedAction(vuexContext, authUser) {
if (!authUser) { //in my case I'm just forcing user back to sign in page, only authorized users allowed//redirect from here this.$router.push({
path: '/signin',
})
}else {
//call your commits or do whatever you want to do
vuexContext.commit("setUser", authUser.email);
}
},
The first part of the code ensures that when the auth state changes in Firestore, this change is communicated to the action that you just created in the store. The second part of the code, the async function in the store accomplishes whatever you want it to do within the store.
I am relatively new in React but I am trying to create a class/method for network call. Nothing complex just a way to make the code readable.
I have a class:
class Auth {
getToken(username, password) {
const endpointOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username: `${username}`, password: `${password}` })
};
fetch(`${Constant.BASE_WP_URL}${Constant.TOKEN_ENDPOINT}`, endpointOptions)
.then(async response => {
const data = await response.json();
if (!response.ok) {
// get error message from body or default to response status
const error = (data && data.message) || response.status;
throw error;
}
return data;
})
.catch(error => {
throw error;
});
}
}
export default Auth;
I am trying to call it using :
import Auth from '../../data/network/Auth';
requestSignIn = (event) => {
event.preventDefault();
this.setState({loading: true})
try {
const authData = Auth.getToken(`${this.state.email}`, `${this.state.password}`);
sessionStorage.setItem('authToken', authData.token)
} catch (error) {
console.log("Connection to WP - Auth Token failed ")
console.error(error);
}
}
but React is complaining because getToken is not a function. I am trying to create a class Auth to have inside all methods/functions I need related to Auth process.
Also, is it the right way to handle the result ? is the try/catch as done works or should I do it differently as the getToken is an API call.
Any idea ?
pretty sure, it's easy but I can't find any interesting topics on Google.
Thanks
I think, if you want to use function directly in OOP of JavaScript, you must put static keyword in front of the function name.
In your auth file
static class Auth {
static getToken(username, password) {
...
}
}
In your index file
import Auth from '../../data/network/Auth';
const authData = Auth.getToken(`${this.state.email}`, `${this.state.password}`);
If you don't have static in front of the function name. You have to create a new instance of the class Auth in order to use the function inside.
import Auth from '../../data/network/Auth';
const AuthInit = Auth();
authData = AuthInit.getToken(`${this.state.email}`, `${this.state.password}`);
===========================
Update for applying asynchronous method
// ====== auth file
static class Auth {
static async getToken(username, password) {
...
// assign fetched data to data_fetch
const data_fetch = fetch(`${Constant.BASE_WP_URL}${Constant.TOKEN_ENDPOINT}`, endpointOptions)
.then(async response => {
const data = await response.json();
if (!response.ok) {
// get error message from body or default to response status
const error = (data && data.message) || response.status;
throw error;
}
return data;
})
.catch(error => {
throw error;
});
return data_fetch;
}
}
// ======= index file
import Auth from '../../data/network/Auth';
...
requestSignIn = async (event) => { // put async in front of your function
// the function outside (requestSignIn) must be async type
// in order to use await keyword for getToken() function
event.preventDefault();
this.setState({loading: true})
try {
// because your getToken function is now a async function, you can
// use "await" keyword in front of it to wait for fetching data to finish
const authData = await Auth.getToken(`${this.state.email}`, `${this.state.password}`);
sessionStorage.setItem('authToken', authData.token)
} catch (error) {
console.log("Connection to WP - Auth Token failed ")
console.error(error);
}
}
Hope this would help
but React is complaining because getToken is not a function
You've defined getToken as a method of an Auth instance, not a static function.
But you don't need an Auth class here at all, just use the proper exports/imports.
replace the Auth-class with:
export function getToken(username, password) {
//...
};
and you can either
/// import all exports from that file under the name `Auth`
import * as Auth from '../../data/network/Auth';
// ...
const authData = Auth.getToken(...);
or
// import these specific exports from that file.
import { getToken } from '../../data/network/Auth';
// ...
const authData = getToken(...);
The last option has the advantage that it can be tree-shaken. If You have some build-process, the compiler can eliminate all the pieces of code that you don't use; especially useful for libraries.
Edit:
Even if you want to keep the default import and import the entire thing, imo. it makes more sense to use a simple Object rather than a class with static methods.
function getToken(username, password) {
//...
}
export default {
getToken
};
In you class definition add static in front of your function to be
class Auth {
static async getToken(username, password) {
const endpointOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username: `${username}`, password: `${password}` })
};
try {
const response = await fetch(`${Constant.BASE_WP_URL}${Constant.TOKEN_ENDPOINT}`, endpointOptions)
const data = await response.json();
if (!response.ok) {
const error = (data && data.message) || response.status;
throw error;
}
return data;
} catch (error) {
throw error
}
}
}
export default Auth;
then you will be able to call it as static function.
and requestSignIn will be using it in the following code
requestSignIn = async (event) => {
event.preventDefault();
this.setState({ loading: true })
try {
const authData = await Auth.getToken(`${this.state.email}`, `${this.state.password}`);
sessionStorage.setItem('authToken', authData.token)
} catch (error) {
console.log("Connection to WP - Auth Token failed ")
console.error(error);
}
}