localstorage returning object on reload - vue.js

i am using vue.js with vuex
In my vuex action i am calling an external api like this:
//actions.js
getStudent({ commit }) {
new Promise((resolve, reject) => {
student.getStudent()
.then(response => {
localStorage.setItem("userInfo", JSON.stringify(response.data.userData))
commit('UPDATE_USER_INFO', JSON.stringify(response.data.userData), { root: true })
resolve(response)
})
}
}
In this function userdata is set as a localstorage item.
I also call a mutation with commit
when this function is executed for the first time everything works fine with for example this code:
//state.js
const userInfoLocalStorage = JSON.parse(localStorage.getItem("userInfo"))
const setUserRole = () => {
const userRole = userInfoLocalStorage ? userInfoLocalStorage.role : 'student'
return userRole
}
const state = {
Role: setUserRole()
}
Now whenever i reload the page JSON.parse returns the error Unexpected token o in JSON at position 1 and when i remove JSON.parse it returns [object Object]. But when i use JSON.stringify it returns a json object but this works only on first load.
I find it very confusing
Please help me clear out what i should use for best practice.

The problem is on this line:
const userRole = userInfoLocalStorage ? JSON.parse(userInfoLocalStorage).role : 'student'
You're calling JSON.parse on an object (userInfoLocalStorage) that has already been deserialized with JSON.parse on the line above:
const userInfoLocalStorage = JSON.parse(localStorage.getItem("userInfo"))
Instead, just do const userRole = userInfoLocalStorage ? userInfoLocalStorage.role : 'student'

Related

Nuxt: How to access store in rollbar.js WITHOUT using localStorage?

I am using Nuxt and Rollbar. I have a user id state in store.
My question is, how can I set this user id as a custom payload in the transformer function in rollbar.js WITHOUT using localStorage?
Here is my code:
// plugins/rollbar.js
const transformer = function(payload) {
payload.user_id = user_id_from_store // how to get this from store?
}
// store/index.js
export const state = () => ({
userId: ''
})
export const mutations = {
setUserId(state, userId) {
state.userId = userId
}
}
//components/MyComponent.vue
methods: {
fetch() {
const userId = fetchUserId()
this.$store.commit('setUserId', userId)
}
}
Things I have tried:
In rollbar.js, create and export a function which takes a context object as argument. Then call this function in transformer function to get user_id:
// plugins/rollbar.js
const getUserId = context => {
const user_id = context.store.state.userId
return user_id
}
const transformer = function(payload) {
payload.user_id = getUserId()
}
export default getUserId
When I console.log(context.store)in getUserId function, I got a Store object, but calling the function in transformer function threw Rollbar: Error while calling custom transform() function. Removing custom transform(). TypeError: Cannot read property 'store' of undefined.
At the end, OP succeeded thanks to inject, more info available here: https://nuxtjs.org/docs/2.x/directory-structure/plugins#inject-in-root--context
This one is indeed needed for libraries that are not directly into the Vue ecosystem but that we wish to have working in our Nuxt app.

Parse JSON to model in React Native getting undefined

I'm trying to map my JSON Object to a model class like that:
export class Product {
constructor(props) {
this.name = props.Name
this.items = props.Items
this.price = props.Price
this.productID = props.ProductID
this.medias = props.Medias
}
}
But when I get JSON and try to parse to my Model I'm getting the following error
TypeError: undefined is not an object (evaluating 'mostSoldProductsApiResponse.map'
There's my parse code:
const mostSoldProductsApiResponse = await mostSoldProductsApiCall.json().Products;
const arrayProducts = mostSoldProductsApiResponse.map(function(item) {
return new Product(item.Product)
})
If I don't parse the JSON Object to new Product() constructor, the code works fine. But I would like to organize the code. Therefore I would like to implement Product class.
It might be you are using await not on what you expect.
The line await mostSoldProductsApiCall.json().Products is actually first returning a promise, then awaiting on the resulting promise field Products which is undefined because it is not the result of the promise.
something equivalent to:
const promise = mostSoldProductsApiCall.json() // this is the promise
const unresolvedProducts = promise.Products // this is undefined
const mostSoldProductsApiResponse = await unresolvedProducts // this resolves to undefined
Solution
Use parenthesis to await on the actual promise, like so:
const mostSoldProductsApiResponse = (await mostSoldProductsApiCall.json()).Products
Another option:
const mostSoldProductsApiResponse = await mostSoldProductsApiCall.json()
const arrayProducts = mostSoldProductsApiResponse.Products.map(function(item) {
return new Product(item.Product)
})
Hope this helps!

The async-await does not work properly with useEffect() in react native. The code does not re render properly

Update
I think the problem is that the credentials array which I fill from the response of the fetchCredentials() function does not get filled quickly so the array becomes empty so no change in length occurs, is there any way to wait until the array gets filled? Also how to make the first fetch method runs always but make the UI renders only if the offeredCredentialsArraySize changes. Also I am using a flat list to list the offerred credentials so will the extraData prop help me? *
I have a problem in useEffect() and the await. I need to re render the code each time the offeredCredentialsArraySize changes, I tried everything but nothing seems to work.
I think the problem is in the await in the fetchCredentials() function, as I understand the await should make the code wait until this method finishes and returns the result and then the fetchOfferedCredentials() should get executed where the size of the array changes, followed by the console.log() but this is not the case, the console.log() prints in the beginning and does not wait for the fetch and the await to finish.
To make the problem more clear, the fetchCredentials() returns as a result an array of credentials, next I check in the fetchOfferedCredentials() function if the array returned from the first function contains any credentials in the "offered" state, if so, I then need to re render and print them. Also inside the fetchOfferedCredentials() I need to remove some of these credentials after the user accepts the offer so I do so again by checking if the state of any of the credentials which are stored in the array containing the result of the fetchCredentials() method changed to "issued" I then remove this offeredCredential from the offered array so its size changes once more and then I will also need to re render.
So to sum up I need the fetch to run all the time and whenever the size of the offeredCredentials array changes I need to re render the UI but I think there is a problem in the await so any help?
Bellow is the code.
Thank you in advance.
const [credentials, setCredentials] = React.useState([]);
const [offeredCredentials,setOfferedCredentials] = React.useState([]);
const [arraySize2, setArraySize2] = React.useState(0);
const [connectionDetailsArray, setConnectionDetailsArray] = React.useState();
const [connectionDataArray, setConnectionDataArray] = React.useState([]);
const [connectionDetailsArraySize, setConnectionDetailsArraySize] = React.useState(0);
const [count, setCount] = React.useState(0);
const [offeredCredentialsArraySize,setOfferedCredentialsArraySize] = React.useState(0);
React.useEffect(() => {
fetchCredentials();
fetchOfferedCredentials();
console.log("This should be printed after the fetch")
},[offeredCredentialsArraySize]);
async function fetchCredentials() {
const res = await fetch('https://api.streetcred.id/custodian/v1/api/' + walletID + '/credentials', {
method: 'GET',
headers: {
Authorization: 'Bearer ',
XStreetcredSubscriptionKey: '',
Accept: 'application/json',
},
});
res.json().then(res => setCredentials(res)).then(setArraySize2(credentials.length));
}
async function fetchOfferedCredentials()
{
setCount(count+1);
for (let index = 0; index < arraySize2; index++)
{
if(credentials[index].state=="Offered")
{
setOfferedCredentials(addConnectionDetails(offeredCredentials,credentials[index].credentialId, credentials[index]) );
console.log(offeredCredentials);
}
}
for (let index = 0; index < offeredCredentials.length; index++)
{
let tempConnectionID= offeredCredentials[index].connectionId;
const res = await fetch('https://api.streetcred.id/custodian/v1/api/'+walletID+'/connections/'+tempConnectionID, {
method: 'GET',
headers: {
Authorization: 'Bearer L2JBCYw6UaWWQiRZ3U_k6JHeeIkPCiKyu5aR6gxy4P8',
XStreetcredSubscriptionKey: '4ed313b114eb49abbd155ad36137df51',
Accept: 'application/json',
},
});
res.json().then(res => setConnectionDetailsArray(res));
const obj = { id: connectionDetailsArray.connectionId,credentialId:offeredCredentials[index].credentialId, title: connectionDetailsArray.name, image: connectionDetailsArray.imageUrl };
setConnectionDataArray(addConnectionDetails(connectionDataArray,obj.id,obj));
}
for (let index = 0; index < arraySize2; index++)
{
if(credentials[index].state=="Issued")
{
for (let index2 = 0; index2 < offeredCredentials.length; index2++) {
if(offeredCredentials[index2].credentialId == credentials[index].credentialId)
{
console.log("here")
offeredCredentials.splice(index2,1)
credentials.splice(index,1)
}
}
}
}
if(count<50)
setOfferedCredentialsArraySize(count+1);
if(currArraySize2!=arraySize2)
setCount(count+1);
console.log(offeredCredentials.length);
}
Because fetchCredentials is an async function, it returns a promise. Because you didn't actually return anything in that function, the promise will resolve to undefined. If you want fetchOfferedCredentials() to be called after fetchCredentials is finished, you need to await that promise returned by fetchCredentials().
You might try
React.useEffect(async () => {
await fetchCredentials();
fetchOfferedCredentials();
console.log("This should be printed after the fetch")
},[offeredCredentialsArraySize]);
However, because of 'race conditions' as stated (but not explained) in here and here, you should wrap your function in another async inside the function:
React.useEffect(() => {
const fetchAllCredentials = async() => {
await fetchCredentials();
fetchOfferedCredentials();
console.log("This should be printed after the fetch")
}
fetchAllCredentials()
},[offeredCredentialsArraySize]);

AsyncStorage.getItem is returning undefined

I'm setting a 'session' variable using AsyncStorage in my action file:
axios
...
// Session variable
AsyncStorage.setItem('userID', response.data.toString()).then((user) => {
this.setState({ user });
});
// Send to next page
NavigationService.navigate('Main');
Then, in my page, I tried to get the value:
...
render() {
AsyncStorage.getItem('userID')
.then((value) => {
const data = JSON.parse(value);
console.log('userID ', data.name);
});
...
It is returning 'userID undefined'. Why is it happening?
Thanks
The problem with the code you've written is that userId has the value 10 but when you call console.log you're treating it like an object with an attribute name. The correct code would look like:
...
render() {
AsyncStorage.getItem('userID')
.then((value) => {
const userId = JSON.parse(value);
console.log('userID ', userId); // This line changed
});
...

Get item from AsyncStorage in React Native

I have a list of companies in React Native.
When I click on one of those companies I get the url of the API that is used for selected company. Then I store it to AsyncStorage and then I show the login screen. The function is as follows:
selectCompany(data_url, e) {
AsyncStorage.setItem("data_url", JSON.stringify(data_url), () => this.props.login());
}
Then on login page if I click on sign in button I go to the onLogin function, the function is as follows:
onLogin: function() {
fetch(data.url + '/manager/api/v1/obtain-auth-token/', })
.then(function(body) {
return body.json();
}).then(function(json) {
.....
}).catch(function() {
....
});
},
And data.url comes from data.js file, and I try to get url from the data.js file as follows:
let data_url = AsyncStorage.getItem("data_url").then(json => JSON.parse(json));
module.exports = {
url: data_url,
.....
}
But it doesn't work. Any advice?
AsyncStorage is async, therefore data_url will not be defined until it's retrieved what its looking for, you would need to move the fetch into the promise thats returned from the get so it will run it once it's done getting the data. This might be one way you tackle it:
const data_url = () => AsyncStorage.getItem("data_url"); //change this into a function
module.exports = {
url: data_url,
.....
}
now inside your component...
onLogin: function() {
data.url().then((url) => {
fetch(JSON.parse(url) + '/manager/api/v1/obtain-auth-token/', })
.then(function(body) {
return body.json();
}).then(function(json) {
.....
}).catch(function() {
....
});
});
},
AsyncStorage.getItem is a promise and needs to await for response rather than accessing direct and the function calling it should be defined as async. Here is an example to retrieve from AsyncStorage..
export async function getAccessKey(){
let accessToken = await AsyncStorage.getItem(ACCESS_TOKEN);
return accessToken;
}