Retrun a value from another component? - javascript

can someone explain to me how can I return a value from another component?
I tried the following:
const ReturnText = () => {
return 'Returend text'
}
export default ReturnText;
And i try to call it in Foo like this
import ReturnText from '../ReturnText'
let someText;
const Foo = (props) => {
someText = ReturnText()
console.log(someText) // is shown as undefined in the debugger
}
But when I try to log the someText variable I get undifend.
EDIT:
It seems the code above works. but maybe I oversimplified my issue:
Here is my actual code (that I thought is identical)
import Geolocation from "react-native-geolocation-service";
let hasLocationPermission = true;
const LocateMe = () => {
if (hasLocationPermission) {
Geolocation.getCurrentPosition(
(position) => {
console.log(position);
return position;
},
(error) => {
// See error code charts below.
console.log(error.code, error.message);
},
{ enableHighAccuracy: true, timeout: 15000, maximumAge: 10000 }
);
}
}
export default LocateMe;
I try to call the LocateMe in Foo and assign the returned position to a variable (ant that variable gives me undefined)

Because getCurrentPosition is an async process wrap the code in a promise and return that. It will resolve the promise with the data when the process is complete.
You can then decide if you want to use async/await or a traditional then to access the data when its returned.
function locateMe() {
const config = { enableHighAccuracy: true, timeout: 15000, maximumAge: 10000 };
return new Promise((res, rej) => {
function success(position) {
res(position);
}
function error(msg) {
console.log(msg);
}
if (hasLocationPermission) {
Geolocation.getCurrentPosition(success, error, config);
}
});
}
Either async/await:
(async () => {
const position = await locateMe();
console.log(position);
})();
Or then:
locateMe().then(coords => console.log(coords));

From what I see the problem is here that you try to return from a callback function Geolocation.getCurrentPosition which will do nothing and it is expected.
The thing is, if an inner function call is asynchronous, then all the functions 'wrapping' this call must also be asynchronous to 'return' a response.
To get the value from LocateMe I would pass the callback function as a parameter like:
const LocateMe = (callback) =>
And instead of
return position
You do
callback(position)
And then in Foo, you get that value and do whatever you need to do with it.

Related

Javascript function confused syntax

I am a little bit confused with the code below. It's obviously a two arrow function written in es6 code but I do not understand exactly some parts.
The 2nd parameter named done is an empty function that does nothing? Or it is executed with a simple return as the result from the second arrow anonymous function?
the XXXX.load is a promise function that returns some results. How the caller of the Index can get the results of the 2nd parameter done ie done(null, result) ?
What is the equivalent code in es5?
const Index = (name, done = () => {}) => (dispatch, getState) => {
return XXXX.load()
.then((result) => {
dispatch({type:OK});
done(null, result);
})
.catch((error) => {
dispatch({type:ERROR});
done(error);
});
};
Let's go one by one:
Index (name, done = () => {}) defines a default value for done in case none is provided when Index is called. This helps down to road to not do any checks in case done is null/undefined. You could also write it like this
const Index = (name, done) => (dispatch, getState) => {
if (!done) {
done = () => {}
}
}
The caller will just pass a function as the second argument when calling Index.
A general note: Index actually returns a function that will expect a dispatch and/or a getState param.
The 2nd parameter named done is an empty function that does nothing?
It's a parameter. It takes whatever value you give it.
The default value, which is assigned if the caller doesn't pass a second argument, is a function that does nothing. This lets it be called without throwing an undefined is not a function error or having an explicit test to see if it is a function or not.
How the caller of the Index can get the results of the 2nd parameter done ie done(null, result) ?
By passing its own function as the second argument.
What is the equivalent code in es5?
var Index = function(name, done) {
if (!done) done = function() {};
return function(dispatch, getState) {
return XXXX.load()
.then(function(result) {
dispatch({
type: OK
});
done(null, result);
})
.catch(function(error) {
dispatch({
type: ERROR
});
done(error);
});
}
};
The empty function is a default value for done. Default values prevents runtime crashes.
2 and 3 can be understood by seeing below code: (simply run it and see the consoles.
const DEFAULT_FUNCTION_VALUE = ()=> {};
const XXXX = {
load: function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve({data: 'from XXXX.load'});
},2000);
});
}
}
const Index = function(name='', done=DEFAULT_FUNCTION_VALUE) {
return function(dispatch, getState) {
return XXXX.load().then(function(result) {
console.log({result});
done(result);
}).catch(function(error) {
console.log(error);
});
}
}
function doneImplementation(data) {
console.log('Data from done- ', data);
}
Index('', doneImplementation)();

Node.js and Jest: Testing promise loop, count how many times function has been called

I want to test my code using JEST, but I'm having some issues. I want to check, if restart() function has been called.
My code works like this, it's waiting for the data, and if there's no data it's calling the same function again. Basically something like a loop.
myCode.js file:
module.exports = {
getSomething: async () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("");
}, 1000);
});
},
doSomething: async () => {
const data = await module.exports.getSomething();
if (!data) {
return module.exports.restart();
}
return data;
},
restart: async () => {
return module.exports.doSomething();
}
};
myCode.test.js file:
const myCode = require("./exampleCode")
describe("test", () => {
test("Is it doing something more than once?", async () => {
const restartSpy = jest.spyOn(myCode, 'restart');
myCode.doSomething()
expect(restartSpy).toHaveBeenCalledTimes(1);
})
})
My problem is that expect(restartSpy).toHaveBeenCalledTimes(1); is returning false.
The question is - what I'm doing wrong? Is there a way to test this code?
The main problem here is the lack of await before myCode.doSomething(). All your functions are asynchronous, so you need to wait for them to finish before checking the spy:
await myCode.doSomething();
Another issue is the fact that it's an infinite recursion loop - jest will timeout after 5000ms (by default) if you won't modify the code that is calling restart, for example:
doSomething: async (restartCounter = 0) => {
const data = await module.exports.getSomething();
if (!data && ++restartCounter < 2) {
return module.exports.restart(restartCounter);
}
return data;
},
restart: async (restartCounter) => {
return module.exports.doSomething(restartCounter);
}
Actually, I've found a workaround.
describe("test", () => {
test("Is it doing something more than once?", async () => {
myCode.restart = jest.fn()
const restartSpy = jest.spyOn(myCode, 'restart');
await myCode.doSomething()
expect(restartSpy).toHaveBeenCalledTimes(1);
})
})
I'm overwriting restart() function. So now, I'm able to add await to doSomething() function and it will no longer be inifinite loop. Now I can check if the restart function has been called

Declare an Async function

I'm new in React and I'm trying to call an async function, but I get the Unexpected reserved word 'await'. ERROR
So my async function is in a Helper class who is supposed to do all the API call, and I'm calling this Helper class in my Game function
Here is my code from Class Helper :
class Helper {
constructor() {
this.state = {
movieAnswer: {},
profile_path:"",
poster_path:"",
myInit: { method: "GET", mode: "cors" }
}
}
fetchMovieFunction = async (randomMovie) => {
return new Promise((resolve) => {
fetch(`${MOVIE_KEY}${randomMovie}?api_key=${API_KEY}`, this.myInit)
.then(error => resolve({ error }))
.then(response => resolve({ poster_path: response.poster_path }));
});
}
and here is where I call fetchMovieFunction in my game function :
const helper = new Helper();
function Game() {
useEffect(() => {
setRandomMovie(Math.floor(Math.random() * (500 - 1) + 1));
const { poster_path, error } = await helper.fetchMovieFunction(randomMovie)
if (error)
return console.log({error});
setApiMovieResponse({poster_path})
}, [page]);
return ();
}
And I don't understand why on this line const { poster_path, error } = await helper.fetchMovieFunction(randomMovie) I get the Unexpected reserved word 'await'. Error like my function is not declare as an async function
two issues:
You should use await inside an async function
But the callback passed to useEffect should not be async. So, you can create an IIFE and make it async:
useEffect(() => {
(async () => {
setRandomMovie(Math.floor(Math.random() * (500 - 1) + 1));
const { poster_path, error } = await helper.fetchMovieFunction(randomMovie);
if (error) return console.log({ error });
setApiMovieResponse({ poster_path });
})();
}, [page]);
The callback itself shouldn't be async because that would make the callback return a promise and React expects a non-async function that is typically used to do some cleanup.
You will necessarily need to wrap the hook callback logic into an async function and invoke it. React hook callbacks cannot be asynchronous, but they can call asynchronous functions.
Also, since React state updates are asynchronously processed, you can't set the randomMovie value and expect to use it on the next line in the same callback scope. Split this out into a separate useEffect to set the randomMovie state when the page dependency updates, and use the randomMovie as the dependency for the main effect.
useEffect(() => {
setRandomMovie(Math.floor(Math.random() * (500 - 1) + 1));
}, [page]);
useEffect(() => {
const getMovies = async () => { // <-- declare async
const { poster_path, error } = await helper.fetchMovieFunction(randomMovie);
if (error) {
console.log({error});
} else {
setApiMovieResponse({poster_path});
}
};
if (randomMovie) {
getMovies(); // <-- invoke
}
}, [randomMovie]);
FYI
fetch already returns a Promise, so wrapping it in a Promise is superfluous. Since you are returning the Promise chain there is also nothing to await. You can return the fetch (and Promise chain).
fetchMovieFunction = (randomMovie) => {
return fetch(`${MOVIE_KEY}${randomMovie}?api_key=${API_KEY}`, this.myInit)
.then(response => return {
poster_path: response.poster_path
})
.catch(error => return { error });
}
In order to do so, It's not suggested to asynchronize a function as a callback function being used in useEffect() since Effect callbacks are synchronous to prevent race conditions.
the better approach would be inside the useEffect callback
check this out:
useEffect(() => {
async function [name] () {
.....
.....
}
[name]();
},string[])
fetchMovieFunction doesn't need to be async because you're already returning a promise. Instead just return the fetch (also a promise), and catch any errors from that call in that method:
fetchMovieFunction = (randomMovie) => {
try {
return fetch(`${MOVIE_KEY}${randomMovie}?api_key=${API_KEY}`, this.myInit)
} catch(err) {
console.log(err);
}
});
But your useEffect, or rather the function you should be calling within the useEffect, does need to be async (because you're using await, but now you can just pick up the data from the fetch when it resolves.
useEffect(() => {
async function getData() {
setRandomMovie(Math.floor(Math.random() * (500 - 1) + 1));
const { poster_path } = await helper.fetchMovieFunction(randomMovie);
setApiMovieResponse({ poster_path });
}
getData();
}, [page]);

navigator.geolocation.getCurrentPosition function results in undefined when called outside local scope

How can I access the object of the navigator.geolocation.getCurrentPosition success callback outside the function when calling it?
Let say I have a function in a file(called UserLoc) which I am exporting.
export const locateCurrentPosition = () => {
const currentPosition = navigator.geolocation.getCurrentPosition(
position => {
console.log(position);
return position;
},
error => {
console.log(error.message);
return error;
},
{
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 1000
}
);
return currentPosition;
};
Now on one of my component js files, I want to call this function inside the componentDidMount()
const {
locateCurrentPosition
} = require("../Views/components/User/UserMap/UserLoc");
async componentDidMount(){
console.log(locateCurrentPosition())
locateCurrentPosition().then(data=>console.log(data))
}
When I am calling the function inside my componentDidMount, it always returns an undefined. When Im logging this, it prints out the position when inside the local scope (ie first code block above where I use console.log(position). What is the best way to actually retrieve the position object from a successful callback and return it into my componentDidMount when called?
Ive tried promises, then statements with my console log as well as different types of returns, but I always seem to get undefined. The return statements within the locateCurrentPosition function dont seem to work. Any suggestions?
Added arrow after new Promise((resolve,reject)
navigator.geolocation.getCurrentPosition returns undefined, the value returned from calling locateCurrentPosition. Position is only passed to the callback supplied in the call, which can be turned into a promise as required:
export const locateCurrentPosition = () => new Promise((resolve,reject)=> {
navigator.geolocation.getCurrentPosition(
position => {
console.log(position);
resolve(position);
},
error => {
console.log(error.message);
reject(error);
},
{
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 1000
}
);
});
and called using
locateCurrentPosition().then(position=>console.log(position))
See also How do I return the response from an asynchronous call

AWS Lambda returning without waiting for promises

I have a function working perfectly well within a node environment. The function uses promises, with S3 calls and a then and catch to call the callback with relevant 200/500 statusCode and a message body in each of them.
Now I am deploying it as a lambda function with a wrapper around it looking like this:
module.exports.getAvailableDates = (event, context, callback) => {
const lambdaParams = retrieveParametersFromEvent(event);
console.log(`Got the criteria`);
module.exports.getFilteredDates(lambdaParams.startDate,
lambdaParams.endDate, callback);
console.log(`Returning without the internal function results`);
};
The internal function looks like this:
module.exports.function getFilteredDates(startDate, endDate) {
const dateSet = new Set();
return new Promise((resolve, reject) => {
const getAllDates = (isDone) => {
if (isDone) {
const Dates = Array.from(dateSet).join();
resolve(Dates);
return;
}
getTestedDates(startDate, endDate, region, func, memory,
lastDateKey, dateSet).then(getAllDates).catch((error) => {
reject(error);
});
};
lastDateKey = '';
getTestedDates(startDate, endDate, region, func, memory,
lastDateKey, dateSet).then(getAllDates).catch((error) => {
reject(error);
});
});
}
And the even more internal function looks similar, only it actually queries the S3 database and returns the list of keys from it that match the date criteria.
In the AWS CloudWatch logs I see the two prints and only after them the internal function output. My understanding is that the lambda function is not waiting for the internal function with the promises to actually do its work (including the internal waiting on the promises) and returns with a bad status to me. What can I do?
Your last console.log is executed before the callback is executed.
If you want to print the complete statement just before exiting the Lambda, you need to wrap the callback ad wait for the Promise to complete:
import getFilteredDates from '../path/to/file';
module.exports.getAvailableDates = (event, context, callback) => {
const lambdaParams = retrieveParametersFromEvent(event);
console.log(`Got the criteria`);
getFilteredDates(lambdaParams.startDate,lambdaParams.endDate)
.then( result => {
console.log(`Returning the internal function results`);
return callback();
})
.catch(callback);
};
I've update the code to work with Promises given the function below.
Your getFilteredDates needs to be reshaped a bit:
Either you to have a third argument to accept the callback inside and handle the Promise chain internally
Or you expose a promise and handle the callback externally in the main scope.
Let's refactor it to just return a Promise and handle the callback outside:
function getFilteredDates(startDate, endDate) {
const dateSet = new Set();
return new Promise((resolve, reject) => {
const getAllDates = (isDone) => {
if (isDone) {
const Dates = Array.from(dateSet).join();
resolve(Dates);
return;
}
getTestedDates(startDate, endDate, region, func, memory,
lastDateKey, dateSet).then(getAllDates).catch((error) => {
reject(error);
});
};
lastDateKey = '';
getTestedDates(startDate, endDate, region, func, memory,
lastDateKey, dateSet).then(getAllDates).catch((error) => {
reject(error);
});
});
}
module.exports = getFilteredDates;
OK, figured it out, it was my bad. The inner function that called the callback with the status code didn't have a null when returning 200 (success) and that failed lambda over and over again. Anyway, I rewrote my lambda to be:
module.exports.getAvailableDates = (event, context, callback) => {
const lambdaParams = retrieveParametersFromEvent(event);
getFilteredDates(lambdaParams.startDate, lambdaParams.endDate)
.then(Dates => callback(null, { statusCode: 200, body: Dates}))
.catch(error => callback({ statusCode: 500, body: error}));
};
And now it works fine. Thanks for anyone who tried helping!
Oren

Categories

Resources