AsyncStorage works only when app is reloaded - javascript

i set my values in Async storage while logging
fetch('http://xxxxx/xxxx/getUserDetails.php', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
user_id: this.state.userEmail,
})
})
.then((response) => response.json())
.then((responseJson) => {
const name = responseJson[0]['name'];
const profilePicture = responseJson[0]['profile_picture'];
const userId = responseJson[0]['id'];
const loginMode = responseJson[0]['login_mode'];
AsyncStorage.setItem('active', 'true');
AsyncStorage.setItem('userEmail', this.state.userEmail);
AsyncStorage.setItem('name', name);
AsyncStorage.setItem('profilePicture', profilePicture);
AsyncStorage.setItem('userID', userId);
AsyncStorage.setItem('loginMode', loginMode)
setTimeout(async () => {
this.setState({ isLoading: false })
this.props.navigation.navigate('userScreen');
}, 500)
})
.catch((error) => {
console.log(error);
})
}
and delete those while logging out.
fetch('https://xxxxxx/xxxx/userLogout.php', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: userEmail
})
}).then((response) => response.json())
.then(async (responseJson) => {
try {
const keys = await AsyncStorage.getAllKeys();
await AsyncStorage.multiRemove(keys);
this.props.navigation.toggleDrawer();
this.setState({ isLoading: false })
this.props.navigation.navigate('loginScreen');
} catch (error) {
console.log("Error clearing app data");
}
}).catch((error) => {
console.log(error);
})
but again if i login with new user the old user details is shown in login page. if i reload my app the new values stored in async storage is shown why this is happen and this is not happening?
I am using the AsyncStorage here.
async componentDidMount() {
const userEmail = await AsyncStorage.getItem('userEmail');
const name = await AsyncStorage.getItem('name');
const profilePicture = await AsyncStorage.getItem('profilePicture');
const userID = await AsyncStorage.getItem('userID');
this.getWish();
this.getAddFunction();
this.setState({ userEmail })
this.getResumeVideo(userEmail);
this.getDemoVideo();
this.getClass();
this.setState({
userEmail,
name,
profilePicture,
userID
})
this.getNotificationCount(userID);
Orientation.lockToPortrait();
this._unsubscribe = this.props.navigation.addListener('focus', () => {
this.getAddFunction();
this.getDemoVideo();
this.getResumeVideo(this.state.userEmail);
this.getClass();
this.getNotificationCount(userID);
});
}

The only place you are calling setState and tells react it should assign new value to state (and render...) it at componentDidMount, therefore React don't know it should render again.
When assigning new value to AsyncStorage you might also call setState
fetch('http://xxxxx/xxxx/getUserDetails.php', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
user_id: this.state.userEmail,
})
})
.then((response) => response.json())
.then((responseJson) => {
const name = responseJson[0]['name'];
const profilePicture = responseJson[0]['profile_picture'];
const userId = responseJson[0]['id'];
const loginMode = responseJson[0]['login_mode'];
AsyncStorage.setItem('active', 'true');
AsyncStorage.setItem('userEmail', this.state.userEmail);
AsyncStorage.setItem('name', name);
AsyncStorage.setItem('profilePicture', profilePicture);
AsyncStorage.setItem('userID', userId);
AsyncStorage.setItem('loginMode', loginMode)
setTimeout(async () => {
this.setState({ isLoading: false })
this.props.navigation.navigate('userScreen');
}, 500)
// here
this.setState({
name,
profilePicture,
userID
})
})
.catch((error) => {
console.log(error);
})
}

Related

how to use Access-Tokens for CRUD REACT JS

Given is an application for managing users. Following help files are used for this purpose:
AuthenticationAction.js
ManagementAction.js
AuthenticationAction.js is used for authentication:
export function authenticateUser(userID, password) {
console.log("Authenticate")
return dispatch => {
dispatch(getAuthenticateUserPendingAction());
login(userID, password).then(userSession => {
const action = getAuthenticationSuccessAction(userSession);
dispatch(action);
}, error => {
dispatch(getAuthenticationErrorAction(error));
}).catch(error => {
dispatch(getAuthenticationErrorAction(error));
})
}
}
function login(userID, password) {
const hash = Buffer.from(`${userID}:${password}`).toString('base64')
const requestOptions = {
method: 'POST',
headers: {
'Authorization': `Basic ${hash}`
},
};
return fetch('https://localhost:443/authenticate', requestOptions)
.then(handleResponse)
.then(userSession => {
return userSession;
});
}
function handleResponse(response) {
console.log(response)
const authorizationHeader = response.headers.get('Authorization');
return response.text().then(text => {
if (authorizationHeader) {
var token = authorizationHeader.split(" ")[1];
}
if (!response.ok) {
if (response.status === 401) {
logout();
}
const error = response.statusText;
return Promise.reject(error);
} else {
let userSession = {
/* user: data, */
accessToken: token
}
return userSession;
}
});
}
ManagementAction.js is there for the Crud Functions.
export function createUser(userID, username, password) {
console.log("Create a User")
return dispatch => {
dispatch(getShowUserManagementAction());
createaUser(userID, username, password).then(userSession => {
const action = getShowUserManagementActionSuccess(userSession);
dispatch(action);
}, error => { dispatch(getShowUserManagementErrorAction(error)); }).catch(error => { dispatch(getShowUserManagementErrorAction(error)); })
}
}
function createaUser(userID, username, password) {
const token = "whatever"
const requestOptions = {
method: 'POST',
headers: { 'Authorization': `Basic ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ userID: userID, userName: username, password: password })
};
console.log(requestOptions)
return fetch('https://localhost:443/user/', requestOptions)
.then(handleResponse)
.then(userSession => {
return userSession;
});
}
question:
Now if I want to use the createaUser function instead of the hardcoded token value with the accestoken I created in login, how do I get the accesstoken and how do I have to rewrite the createaUser function ?
you can store the token you created in the local storage like this:
AuthenticationAction.js
let userSession = {
/* user: data, */
accessToken: token
}
localStorage.setItem("token", userSession.accessToken)
and you can access it as below:
ManagementAction.js
function createaUser(userID, username, password) {
const token = localStorage.getItem("token")
const requestOptions = {
method: 'POST',
headers: { 'Authorization': `Basic ${token}`, 'Content-Type': 'application/json' },
then
so you can send your token value with the request

React Redux Thunk with callback to another function -- TypeError: Cannot read property 'then' of undefined

I am using react+redux.
I have a modal form with data and images and on success I need to close the modal else display error returned from redux. In the dispatch function I have 1 more callback function to store images to S3. I am returning promise from the redux-thunk but I keep getting "TypeError: Cannot read property 'then' of undefined".
Component
handleSubmit = e => {
e.preventDefault();
if(this.isFieldEmpty()){
this.setState({ message: "All fields are mandatory with at least 1 pic" });
return;
} else {
this.setState({ message: "" });
}
const data = {
name: this.state.name,
description : this.state.description,
points : this.state.points,
attributes : this.state.attributes,
images : this.state.images,
created_by: localStorage.getItem('id'),
}
this.props.createItem(data).then(() => {
this.hideModal();
})
}
const mapDispatchToProps = dispatch => {
return {
createItem: data => {
return dispatch(createItem(data))
},
};
};
Action
const saveItemImages = (images,successcb, failurecb) => {
if(images.length > 0){
const formData = new FormData();
for(var x = 0; x<images.length; x++) {
formData.append('image', images[x])
}
const token = localStorage.getItem('token');
fetch(`${backendUrl}/upload/item-images/`, {
method: "POST",
headers: {
'Authorization': `Bearer ${token}`
},
credentials: 'include',
body: formData
})
.then(res => {
if(res.status === 200){
res.json().then(resData => {
successcb(resData.imagesUrl);
});
}else{
res.json().then(resData => {
failurecb(resData.message);
})
}
})
.catch(err => {
console.log(err);
});
} else {
successcb([]);
}
}
export const createItem = data => { return (dispatch) => {
saveItemImages(data.images, imagesUrl => {
data.images = imagesUrl;
return fetch(`${backendUrl}/admin/createItem`, {
method: 'POST',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json',
'Authorization': `Bearer ${data.token}`
},
credentials: 'include',
body: JSON.stringify(data)
})
.then(res => {
if(res.status === 200){
res.json().then(resData => {
dispatch({
type: ADMIN_CREATE_ITEM_SUCCESS,
payload: resData
})
return true;
});
}else{
console.log("Save failed");
res.json().then(resData => {
dispatch({
type: ADMIN_CREATE_ITEM_FAILED,
payload: {
message: resData.message
}
})
})
}
})
.catch(err => {
dispatch({
type: ADMIN_CREATE_ITEM_FAILED,
payload: {
message: `Internal Error -- ${err}`
}
})
});
}, failedMessage => {
let payload = {responseMessage: failedMessage}
dispatch({
type: ADMIN_CREATE_ITEM_FAILED,
payload: payload
})
});
};
};
Thanks in advance for any help
You should return a Promise to create async flow for the action like this:
export const createItem = data => dispatch => new Promise((resolve, reject) => {
// do something was a success
resolve();
// do something was a fail
reject();
});

How to set a new token when the token expired?

I have created the function getNewToken, in which I am fetching a new token on the basis of refresh_token and setting it in localstorage. Where to check the Unauthorized 401 error and call this function this.getNewToken()?
if (error.status === 401) {
     this.getNewToken ();
}
axios.defaults.baseURL = localStorage.getItem('domain');
class App extends Component {
constructor (props) {
super(props);
this.state = {
items: []
}
}
componentDidMount() {
axios.defaults.baseURL = localStorage.getItem('domain');
axios({
url: "/api/v1/items",
method: "GET"
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(response => {
console.log(response.data)
this.setState({
items: response.data,
});
})
.catch(error => {
if(error.status === 401) {
console.log(error.status);
this.getNewToken();
}
})
}
getNewToken = () => {
axios.defaults.baseURL = localStorage.getItem('domain');
const url = '/api/refresh_token';
const data = qs.stringify({
grant_type: 'refresh_token',
client_secret: ****,
client_id: ****,
refresh_token: ****
});
const config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
axios({
method: 'post',
url,
data,
config
})
.then(res => {
if (res.status === 200) {
localStorage.setItem('token', JSON.stringify(res.data))
this.setState({
token: res.data
})
}
}).catch(err => {
console.error(err);
});
}
render () {
return (
<div>
</div>
)
}
}

In react, how to update state after doing a fetch?

I have a state which is an empty array:
constructor(props) {
super(props);
this.state = {
test_steps: [],
};
}
I need to fill up that state with the following data that get when I do a GET request:
See image
UPDATED:
export function copyTestScenarioLog(tSL) {
console.log("\nCalled copyTestScenarioLog");
let url = config.base_url + `/test_scenario_logs`;
return fetch(url, {
method: 'POST',
headers: {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + getUserToken() },
body: JSON.stringify({
_id: tSL._id['$oid']
})
})
.then(res => res.json())
.then(data => {
getTestStepLogs(data)
return data;
})
.catch(err => console.log(err));
}
export function getTestStepLogs(data) {
const id = data.test_step_logs[0].$oid;
let url = config.base_url + `/test_step_logs/${id}`;
return fetch(url, {
method: 'GET',
headers: { 'Authorization': 'Bearer ' + getUserToken() }
})
.then(res => res.json())
.then(data => {
console.log(data)
return data
})
.catch(err => console.log(err));
}
How do I update my state after doing a GET fetch?
This is full react component code, you see how I call your funciton in componentDidMount, and in here I pass 'this' as an argument to copyTestScenarioLog.
import React, { Component } from 'react';
import copyTestScenarioLog from './copyTestScenarioLog';
class Component1 extends Component {
constructor(props) {
super(props);
this.state = {
test_steps: []
};
}
componentDidMount() {
var reactComponent = this;
copyTestScenarioLog('i dont konw that is tsl', reactComponent);
}
render() {
return (
<div></div>
);
}
}
export default Component1;
In 'copyTestScenarioLog', I get that ( refers to react component), and use setState function in react.
export function copyTestScenarioLog(tSL, reactComponent) {
console.log("\nCalled copyTestScenarioLog");
let url = config.base_url + `/test_scenario_logs`;
return fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + getUserToken() },
body: JSON.stringify({
_id: tSL._id['$oid']
})
})
.then(res => res.json())
.then(data => {
getTestStepLogs(data)
reactComponent.setState({
test_steps: data
});
return data;
})
.catch(err => console.log(err));
}
But basically I don't use this approach, I just wanted to show that how its done, I usually use await/async or function generators, because they are better approaches. Search about them and learn to use them.
you can pass onSuccess function into your getTestStepLogs and update your state.
export function getTestStepLogs(data , onSuccess) {
const id = data.test_step_logs[0].$oid;
let url = config.base_url + `/test_step_logs/${id}`;
return fetch(url, {
method: 'GET',
headers: { 'Authorization': 'Bearer ' + getUserToken() }
}).then(resp => {
if (onSuccess)
onSuccess(resp);
}).catch(err => console.log(err));
}
and when you call getStepLogs pass onSuccess as props:
this.props.getTestStepLogs(data , (resp)=>{
this.setState({test_steps:resp});
})
if you are using the get call at multiple place, you can be little generic and try this approach.
//return here does not do anything right now
export function getTestStepLogs(data) {
return new Promise(function(resolve, reject){
const id = data.test_step_logs[0].$oid;
let url = config.base_url + `/test_step_logs/${id}`;
return fetch(url, {
method: 'GET',
headers: { 'Authorization': 'Bearer ' + getUserToken() }
})
.then(res => res.json())
.then(data => {
console.log(data)
resolve(data);
})
.catch(err => {console.log(err);
reject(err);
});
})
}
async componentDidMount() {
let data = await copyTestScenarioLog();
//now set it to state
}
For an async call, there are three states. Call initiation, call success and call failure. Say "isLoading" represents the status of the call being running in the background.
Initially =>
{
isLoading : false,
data : '',
err : ''
}
Call initiated =>
{
isLoading : true,
data : '',
err: ''
}
Call success =>
{
isLoading : false,
data : response.data
err: ''
}
Call failed =>
{
isLoading :false,
data : '',
err: err
}
Usually, the GET calls of a component are made in componentDidMount. It is also the suggested way as per the react documentation.
componentDidMount(){
//Call Initiation
this.setState({
isLoading : true,
data : '',
err: ''
});
makeApiCall(api).
then((response) => {
this.setState({
isLoading : false,
data : response.data
err: ''
});
},
(err) => {
this.setState({
isLoading :false,
data : '',
err: err
})
})
.catch((err) => {
this.setState({
isLoading :false,
data : '',
err: err
})
})
}

React Redux promise error - (...).then is not a function

Had a look for this in the questions that offered but this was the closest and it didnt really address my problem.
I have a code block (detailed a little way down the page) as part of a larger fetch block.. it gets to this codeblock and also runs fine if this code block is commented out i.e it carrys out a successful fetch etc and returns a JWT no problem but... add this block in and i get the following error:
TypeError: (0 , _localStorageDropDowns.confirmSelectDataExistance)(...).then is not a function
It is referring to this function in another folder (imported correctly)..
export const confirmSelectDataExistance = () => {
const companyStateShortNameJson = localStorage.getItem(COMPANYSTATESHORTNAME)
const statesJson = localStorage.getItem(STATES)
const suburbLocationsJson = localStorage.getItem(LOCATIONS)
if (companyStateShortNameJson || statesJson || suburbLocationsJson) {
console.log('something exists in localstorage')
return true
}
console.log('nothing in localstorage')
return false
}
simple function - returns true or false.
and here is the code block -its failing on the first line:
return confirmSelectDataExistance().then(isConfirmed => {
if (!isConfirmed) {
dispatch({ type: REQUEST_SELECT_DATA })
console.log('gets here!', isConfirmed)
const token = getJwt()
const headers = new Headers({
'Authorization': `Bearer ${token}`
})
const retrieveSelectData = fetch('/api/SelectData/SelectData', {
method: 'GET',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
})
.then(handleErrors)
.then(response => response.json())
.then(selectData => {
dispatch({ type: RECEIVE_SELECT_DATA, payload: selectData })
saveSelectData(selectData)
});
return saveSelectData(selectData);
}
})
From my limited experience the "confirmSelectDataExistance" is a function so why is it saying that its not?
Finally here is the whole action in its entirety so you can see how it that block is called.. as I said - comment the block out and it works perfectly..
export const requestLoginToken = (username, password) =>
(dispatch, getState) => {
dispatch({ type: REQUEST_LOGIN_TOKEN, payload: username })
const payload = {
userName: username,
password: password,
}
const task = fetch('/api/jwt', {
method: 'POST',
body: JSON.stringify(payload),
headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
})
.then(handleErrors)
.then(response => response.json())
.then(data => {
dispatch({ type: RECEIVE_LOGIN_TOKEN, payload: data })
saveJwt(data)
return confirmSelectDataExistance().then(isConfirmed => {
if (!isConfirmed) {
dispatch({ type: REQUEST_SELECT_DATA })
console.log('gets here!', isConfirmed)
const token = getJwt()
const headers = new Headers({
'Authorization': `Bearer ${token}`
})
const retrieveSelectData = fetch('/api/SelectData/SelectData', {
method: 'GET',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
})
.then(handleErrors)
.then(response => response.json())
.then(selectData => {
dispatch({ type: RECEIVE_SELECT_DATA, payload: selectData })
saveSelectData(selectData)
});
return saveSelectData(selectData);
}
})
})
.catch(error => {
clearJwt()
console.log('ERROR - LOGIN!',error)
})
addTask(task)
return task
}
EDIT
I have finally got this to work after hacking away for hours.. Here is the finished action:
export const requestLoginToken = (username, password) =>
(dispatch, getState) => {
dispatch({ type: REQUEST_LOGIN_TOKEN, payload: username })
const payload = {
userName: username,
password: password,
}
const task = fetch('/api/jwt', {
method: 'POST',
body: JSON.stringify(payload),
headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
})
.then(handleErrors)
.then(response => response.json())
.then(data => {
dispatch({ type: RECEIVE_LOGIN_TOKEN, payload: data })
saveJwt(data)
// Now check local storage for dropdown data..
if (!confirmSelectDataExistance()) {
dispatch({ type: REQUEST_SELECT_DATA })
const token = JSON.stringify(data)
const headers = new Headers({
'Authorization': `Bearer ${token}`
})
const retrieveSelectData = fetch('/api/SelectData/SelectData', {
method: 'GET',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
})
.then(handleErrors)
.then(response => response.json())
.then(selectData => {
dispatch({ type: RECEIVE_SELECT_DATA, payload: selectData })
saveSelectData(selectData)
});
}
})
.catch(error => {
clearJwt()
console.log('ERROR - LOGIN!', error)
})
addTask(task)
return task
}
and here is the function it calls:
export const confirmSelectDataExistance = () => {
const companyStateShortNameJson = localStorage.getItem(COMPANYSTATESHORTNAME)
const statesJson = localStorage.getItem(STATES)
const suburbLocationsJson = localStorage.getItem(LOCATIONS)
if (companyStateShortNameJson || statesJson || suburbLocationsJson) {
console.log('something exists in localstorage')
return true
}
console.log('nothing in localstorage')
return false
}
The one thing I changed from the other attempts is that I used "data" instead of calling "getJwt()". I then used the line:
const token = JSON.stringify(data)
to obtain the JWT I just got.
In the end I used #Karin s answer and ran with that. (upvoted by me)
The error is not saying that confirmSelectDataExistance is not a function, it's saying that then isn't a function on what is returned from it, which is a boolean (it would be equivalent to false.then(...), which doesn't work).
If seems like you're trying to use then as a conditional. In that case a simple if statement should work:
if (confirmSelectDataExistance()) {
// do things if it returns true
} else {
// do things if it returns false
}
export const confirmSelectDataExistance = () => {
return new Promise(function (resolve, reject) {
const companyStateShortNameJson = localStorage.getItem(COMPANYSTATESHORTNAME)
const statesJson = localStorage.getItem(STATES)
const suburbLocationsJson = localStorage.getItem(LOCATIONS)
if (companyStateShortNameJson || statesJson || suburbLocationsJson) {
console.log('something exists in localstorage')
resolve(true)
}
console.log('nothing in localstorage')
reject(false)
})
}
Try something like this:
export const confirmSelectDataExistance = new Promise((resolve, reject) => {
const companyStateShortNameJson = localStorage.getItem(COMPANYSTATESHORTNAME);
const statesJson = localStorage.getItem(STATES);
const suburbLocationsJson = localStorage.getItem(LOCATIONS);
if (companyStateShortNameJson || statesJson || suburbLocationsJson) {
console.log('something exists in localstorage');
resolve(true);
}
console.log('nothing in localstorage');
reject(false); // or resolve(false) if you want handle this situation inside then block also
});

Categories