React Native variable getting undefined before running method - react-native

I have a function that calls a method that is in my Helper.js file.
import { getTest } from '../../common/Helper';
...
myMethod() {
...
const test = getTest(this.state.myID);
console.log(test);
}
...
My Helper.js:
export const getTest = (pID) => {
axios.get('http://myserver.com/', {
params: {
method: 'getVacantUnits',
propertyID: pID
}
}).then((response) => {
console.log(response.data);
return response.data;
}).catch((error) => {
// handle error
console.log(error);
return 0;
});
};
It is odd because my output is:
undefined
myDataContent
It looks like that "const test" is receiving undefined before the getTest being run. Why is it happening?
Thanks

It's returning this first since it's not awaiting the result:
console.log(test);
2 easy ways to fix this I am showing below, first with promise:
const test = getTest(this.state.myID).then(response=> console.log(response)).catch(err => console.log(err))
Add in return as well since you need to return from outermost function
export const getTest = (pID) => {
return axios.get('http://myserver.com/', {
params: {
method: 'getVacantUnits',
propertyID: pID
}
}).then((response) => {
console.log(response.data);
return response.data;
}).catch((error) => {
// handle error
console.log(error);
return 0;
});
};
second using async await:
// add in await
export const getTest = async (pID) => {
return axios.get('http://myserver.com/', {
params: {
method: 'getVacantUnits',
propertyID: pID
}
}).then((response) => {
console.log(response.data);
return response.data;
}).catch((error) => {
// handle error
console.log(error);
return 0;
});
};
// here you are awaiting the response before you run console.log
const test = await getTest(this.state.myID);
console.log(test);
You can solve this in several other ways, but I think these are the 2 easiest. Basically think about the fact that those are run synchronously and the console.log executes before the function returns, so if you "wait" then it makes it so the console.log() is dependent on the first function executing first.

Related

jest how can test axios?

No matter how I write, asynchronous problems occur.
test.js:
const auth = require('../methods/auth.js');
describe('test', () => {
test('test', async () => {
expect.assertions(1);
const data = await auth.signin();
return expect(data.success).toBeTruthy();
});
auth.js:
module.exports = {
async signin(data) {
try {
const res = await axios.post('/signin', data);
return res.data;
} catch (error) {
return error.response;
}
},
}
Each execution result is different.
You can test Promises as follows:
test('test awaiting it to resolve', () => {
// Don't await. Note the return; test callback doesn't need to be async
// What I do in my tests as its more readable and the intention is clear
return expect(auth.signin()).resolves.toEqual({success: true});
});
test('test the promises way', () => {
// Not better than above; traditional way; note 'return'
return auth.signin().then(data => { expect(data.success).toBeTruthy() });
});
Detailed notes from jest: https://jestjs.io/docs/asynchronous#promises

React Native UseEffect function is not working according to order

I want to get user's current location and set it into AsyncStorage a array. I will do it in the useEffect hook. But the problem is my functions are not working that according to given order. Here are my code
useEffect(() => {
getUserLocation();
setUserLocation();
check();
}, []);
/*Get User's Currunt Location*/
const getUserLocation = () => {
GetLocation.getCurrentPosition({
enableHighAccuracy: true,
timeout: 15000,
})
.then((location) => {
var lt = location.latitude;
var lg = location.longitude;
setlatitude(lt);
setlongitude(lg);
console.log("getUserLocation", lt, lg);
})
.catch((error) => {
const { code, message } = error;
console.warn(code, message);
});
};
/*Set User's Currunt Location to AsyncStorage*/
const setUserLocation = async () => {
try {
await AsyncStorage.setItem("user_location", JSON.stringify(userLocation));
console.log("setUserLocation", userLocation);
} catch (error) {
console.log("error setting user location");
}
};
const check = () => {
AsyncStorage.getItem("user_location", (err, result) => {
if (result !== null) {
console.log("check", result);
setlatitude(result.latitude);
setlongitude(result.longitude);
} else {
console.log("Data Not Found");
}
});
};
Whenever you use .then you are scheduling your code to run at some point in the future, when the promise has completed. So setUserLocation runs before the then of getUserLocation.
Also, it looks like your getUserLocation set react state, which won't be available until the next render. We use effects to manage this.
// Get the location on mount
useEffect(getUserLocation, []);
// Whenever the location updates, set it into storage
useEffect(() => setUserLocation().then(check), [latitude, longitude]);

How to test Axios reject condition using Jest

I wrote a unit test for some Axios calls in my component. I verified the success path, where the call resolves successfully, but I am not able to verify the failure path, where the call rejects. How do I use mocks to verify this?
Here's a snippet of my FetchImage.vue component:
methods: {
preparedFetch() {
axios.get(this.imageurl).then(result => {
this.imageInformation.title = result.data.title;
this.imageInformation.copyright = result.data.copyright;
this.imageInformation.detailExplanation = result.data.explanation;
this.imageInformation.date = result.data.date;
this.imageInformation.urlinfo = result.data.url;
this.resultArrived = true;
this.$emit('imagefetched',this.imageInformation);
})
.catch( error => {
this.errorMessage = "Information not found";
this.resultArrived = true;
});
}
}
And my test for when the call rejects (for an invalid URL):
describe('Invalid response',async () => {
beforeEach(() => {
axios.get.mockClear();
axios.get.mockReturnValue(Promise.reject({}));
});
it('Invalid URL verfication', async () => {
// Given
const result = {
errorMessage : "Information not found",
resultArrived : true,
fetchStatus : true
};
// Fetch the error result
axios.get.mockReturnValue(Promise.resolve(result));
const fetchwrapper = mount(FetchImage);
fetchwrapper.vm.imageurl = "https://invalid.request.gov";
fetchwrapper.vm.preparedFetch();
await fetchwrapper.vm.$nextTick();
// Validate the result
expect(axios.get).not.toHaveBeenCalledWith('https://api.nasa.gov/planetary/apod?api_key=vME6LAMD7IhEiy7rDmjfIaG6MhiKbu1MNIqxtqd1');
expect(axios.get).toHaveBeenCalledWith("https://invalid.request.gov");
expect(axios.get).toHaveBeenCalledTimes(1);
expect(fetchwrapper.vm.errorMessage.length).not.toEqual(0);
expect(fetchwrapper.vm.errorMessage).toBe("Information not found");
});
});
Your catch block isn't running because the mock return value is using Promise.resolve() when it actually should be Promise.reject():
describe('Invalid response',async () => {
it('Invalid URL verfication', async () => {
// axios.get.mockReturnValue(Promise.resolve(result)); // DON'T DO THIS
axios.get.mockReturnValue(Promise.reject(result));
});
});
You have to reject the value by using the built-in jest method.
describe('Invalid response', async () => {
it('Invalid URL verfication', async () => {
axios.get.mockRejectedValue(result);
});
});

React native await not working in pressed function

I have an async function that uses redux and it calls an API and returns the response from the server:
function xyz() {
return async (dispatch, getState) => {
const { user: { token } } = getState();
return axios.get(API_URL, {
headers: {
Accept: "application/json",
"Content-Type": "application/json",
'jwt': token
}
})
.then(response => {
console.log(response.data.data);
return response.data.data;
})
.catch(function(error) {
console.log('error: ' + error.message);
});
};
}
The mapDispatchToProps function is defined as it follows:
const mapDispatchToProps = (dispatch, ownProps) => {
return {
xyz: () => {
dispatch(actions.xyz());
}
};
};
export default connect(null, mapDispatchToProps)(Container);
I'm trying to call the function xyz from the following function:
abc = async () => {
const { xyz } = this.props;
const result = await xyz();
console.log(result);
}
which is triggered when a button is pressed:
<TouchableOpacity onPressOut={this.abc}>
I see that the console.log into the function abc prints undefined, while the console.log(result.data.data) into xyz prints the expected result. Where am I wrong?
Solution
The error was in the mapDispatchToProps function, which was missing the return. Here it is the correct implementation:
const mapDispatchToProps = (dispatch, ownProps) => {
return {
xyz: () => {
return dispatch(actions.xyz());
}
};
};
export default connect(null, mapDispatchToProps)(Container);
Like I mentioned in the comments, xyz() should return a promise. Double check that the dispatch and getState arguments are getting passed correctly. You'll also need to await the returned axios.get promise. For example:
abc = async () => {
const { xyz } = this.props;
const result = await xyz();
const results = await result();
console.log(results);
}
Here is a snack with a working example.
I don't fully understand what you mean when you say the console.log in xyz prints the expected result, are you speaking about the error.message in your catch? Also, the reason you may be receiving undefined is because function xyz is not Async but rather it returns an async function, thus you should make xyz async such as:
function async xyz () {
// Rest of code
}
For more you can read here

Send single response after multiple updates

I have an array of items that I am passing to an API endpoint (using Sequelize as my ORM). I'm trying to iterate over each item and update it, however I'm getting a Unhandled rejection Error: Can't set headers after they are sent.
stepsController.put = (req, res) => {
const { steps } = req.body;
// Steps is an array of objects that I want to update...
steps.map(step => {
Step.findOne({ where: { id: step.id } })
.then(savedStep =>
savedStep
.update({
order: step.order,
})
.then(success => res.status(200).send(success))
.catch(error => res.send(error))
)
.then(ok => res.status(200).send(ok))
.catch(err => res.send(err));
});
};
I believe this is because it's sending the response for each item. Sequelize's update method is a promise. How can I iterate over all of the items and make sure all of the items are updated before sending a single successful response?
There are three ways you can do
Promise.all
Co
Async Await
1) Here it is , you can use Promise.all :
stepsController.put = (req, res) => {
const { steps } = req.body;
// Steps is an array of objects that I want to update...
Promise.all(steps.map(step => {
return Step.findOne({ where: { id: step.id } }).then(savedStep =>
return savedStep.update({
order: step.order,
})
.catch(error => error)
).catch(err => err)
}))
.then(ok => res.status(200).send(ok))
.catch(err => res.send(err));
};
2) Another way is to use co :
const co = require('co');
stepsController.put = co.wrap(function* (req, res) => {
try {
const { steps } = req.body;
// Steps is an array of objects that I want to update...
for(let i=0;i<steps.length ; i++) {
let savedStep = yield Step.findOne({ where: { id: steps[i].id } });
if(savedStep)
yield savedStep.update({ order: steps[i].order});
}
res.status(200).send();
}
catch(err){
res.send(err);
}
});
3) If you’re using Node 8.0+ , there is no need of any package you can directly use async await :
stepsController.put = async(req, res) => {
try {
const { steps } = req.body;
// Steps is an array of objects that I want to update...
for(let i=0;i<steps.length ; i++) {
let savedStep = await Step.findOne({ where: { id: steps[i].id } });
if(savedStep)
await savedStep.update({ order: steps[i].order});
}
res.status(200).send();
}
catch(err){
res.send(err);
}
};