// ....react component
const [fruitDetail, setFruitDetail] = useState(null);
useEffect(() => {
if (!fruitName) {
return;
}
// Method 1
getFruit(fruitName).then((data) => {
console.log(data);
setFruitDetail(data);
});
// Method 2
getFruit(fruitName).then(setFruitDetail);
}, [fruitName]);
return fruitDetail;
I'm very curious about that why Method 1 and Method 2 are equivalent. Is it a Syntactic sugar ?
You can look at method 1 as an explicit way of calling the function. The .then method gets passed the result of getFruit(fruitName)..which you could name whatever you wanted, in your case you chose to call it data. Then you used that variable, data to make two function calls. So you explicitly refer the response by the variable name data.
In your method 2, the variable is implicit. Meaning, because of the way .then works, Javascript knows .then expects one argument, which is the result of the getFruit(fruitName). The .then method takes the result and passes it as the first argument to setFruitDetail...it would also be the same thing to say getFruit(fruitName).then(response => setFruitDetail(response)).You just don't need to specifically put the response variable since it is the only thing being passed and only thing being used.
then function calls any passed function/callback with the promise result.
setFruitDetail is just a function so is ()=>{} albeit anonymous one. You can also pass console.log and see what it does like this getFruit(fruitName).then(console.log). I would suggest to have a look at basic promise implementation.
Is it a Syntactic sugar ?
No, it is not. Because, it's just the another way to pass callback function.
There is example to make clear:
let api = async () => {
return new Promise((solve, reject) => {
setTimeout(() => solve('result'), 1000);
})
};
//your setFruit is a callback. Let example:
let setFruitDetail = (fruit) => console.log(fruit);
//there is no different when you pass a call back into then function.
api().then(setFruitDetail);
api().then(fruit => setFruitDetail(fruit));
//you can imagine that in then function will get param you input into to call a callback.
let otherApi = (callback) => {
let result = "result";
callback("result");
}
otherApi(setFruitDetail);
otherApi(fruit => setFruitDetail(fruit));
Related
A new javascript question, again, and again...
(Updated)
a is a string where I input a word, it will then be sent to a Dictionary API and do the fetchApi(). After getting the result, if a matches the result[0].word, it will trigger the function Func1(), if not then it will trigger the other function Func2().
What I'd like to ask is there any way to use setInterval() for the function data(result), after deleting the part .then(result => data(result)) in the function fetchApi(a)? Or can I only put setInterval() for both functions Func1() and Func2()?
Thank you very much!
var a = "";
function fetchApi(a) {
let url = `${url}${a}`;
fetch(url).then(res => res.json()).then(result => data(result));
}
function data(result) {
// console.log(result);
if (a == result) {
Func1();
} else {
Func2();
}
}
Putting setInterval() on data() will not do anything because result will never change once it has returned. You need to call the whole fetchApi function again if you're expecting the result to be updated later on.
I have been doing a React course and I am unable to understand double arrow functions correctly. Could someone please explain me this piece of code
export const fetchDishes = () => (dispatch) => {
dispatch(dishesLoading(true));
setTimeout(() => {
dispatch(addDishes(DISHES));
}, 2000);
}
All I understood till now is that fetchDishes is a function which takes no arguments but returns another function named dispatch and the dispatch function calls itself(dispatches an action).
I am looking for a detailed explaination, bonus if you could explain a bit in terms of react too
All I understood till now is that fetchDishes is a function which
takes no arguments but returns another function
Till this point you are right but later it does not return function named dispatch but instead take argument named dispatch which is an callback (or in Reactjs dispatcher or smth else) and this callback is called with those 2 values at very beginning and after 2 seconds.
const DISHES = [1, 2, 3];
const dishesLoading = (someBool) => someBool;
const addDishes = (dishes) => dishes.length;
const fetchDishes = () => (dispatch) => {
dispatch(dishesLoading(true));
setTimeout(() => {
dispatch(addDishes(DISHES));
}, 2000);
};
const fetchDishesDispatcher = fetchDishes();
fetchDishesDispatcher(function someCallbackFunction(value) {
// first outputed value will be result of "dishesLoading(true)" function
// after 2 seconds second value will be outputed with result of "addDishes(DISHES)" function
console.log(value);
});
This is an example of using a middleware in redux such as redux-thunk or redux-saga. It provides a third-party extension point between dispatching an action, and the moment it reaches the reducer, which means it adds a protection layer between action and reducer which can be used to call asynchronous API and check for errors before hand, routing, crash reporting etc.
You can read more about it here and a thread on stackoverflow too.
Using classic JS functions, the code could be rewritten like this:
export const fetchDishes = function() {
return function(dispatch) {
dispatch(dishesLoading(true));
setTimeout(() => {
dispatch(addDishes(DISHES));
}, 2000);
}
}
So the function fetchDishes returns function, whose argument is dispatch of type function.
To be honest, I don't understand how this kind of nesting is helpful if the first function doesn't have any arguments (one could just export the function returned by fetchDishes). To see what is the purpose of double arrow functions, read What do multiple arrow functions mean in javascript? .
I'm relatively new to js so please forgive me if my wording isn't quite right. I've also created a jsfiddle to demonstrate the issue.
Overview
In the app I'm working on, I have a function with a jquery ajax call, like this:
function scenario1(ajaxCfg) {
return $.ajax(ajaxCfg)
}
I want to change this function, but without in any way changing the inputs or outputs (as this function is called hundreds of times in my application).
The change is to make a different ajax call, THEN make the call specified. I currently have it written like this:
function callDependency() { //example dependency
return $.ajax(depUri)
}
function scenario2(ajaxCfg) {
return callDependency().then(() => $.ajax(ajaxCfg))
}
Desired Result
I want these two returned objects to be identical:
let result1 = scenario1(exampleCall)
let result2 = scenario2(exampleCall)
More specifically, I want result2 to return the same type of object as result1.
Actual Result
result1 is (obviously) the result of the ajax call, which is a jqXHR object that implements the promise interface and resolves to the same value as result2, which is a standard promise.
Since result2 is not a jqXHR object, result2.error() is undefined, while result1.error() is defined.
I did attempt to mock up these methods (simply adding a .error function to the return result, for example), but unfortunately even when doing this, result1.done().error is defined while result2.done().error is undefined.
Wrapping (or unwrapping) it up
In a nutshell, I want to return the jqXHR result of the .then() lambda function in scenario2 as the result of the scenario2 function. In pseudocode, I want:
function scenario2(ajaxCfg) {
return callDependency().then(() => $.ajax(ajaxCfg)).unwrapThen()
} //return jqXHR
What about something like this? The approach is a little different, but in the end you can chain .done() etc. to the scenario2() function:
const exampleCall = { url: 'https://code.jquery.com/jquery-1.12.4.min.js'};
const depUri = { url: 'https://code.jquery.com/jquery-1.12.4.min.js'};
function callDependency() { //example dependency
return $.ajax(depUri).done(() => console.log('returned callDependancy'))
}
let obj = { //creating an object with the scenario2 as a method so that I can bind it with defer.promise()
scenario2: function(ajaxCfg) {
return $.ajax(ajaxCfg).done(() => console.log('returned senario2')) // Purposely NOT calling the exampleCall() function yet
}
}
defer = $.Deferred(); // Using some JQuery magic to be able to return a jqXHR
defer.promise(obj); // Set the object as a promise
defer.resolve(callDependency()); // Invoking the callDependency() by default on promise resolve
obj.done(() => {
obj.scenario2() // Resolving so the callDependency() function can be called
}).scenario2(exampleCall).done(() => { // Here you can invoke scenario2 and FINALLY chain whatever you want after everything has been called
console.log('Here I can chain whatever I want with .done\(\) or .fail\(\) etc.')
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
What I think is cool about this way of doing it is that you can just keep adding methods to the object that you created, and then all your secondary functions that are built on top of callDependency() can be in one place. Not only that, but you can reuse those same methods on top of other AJAX calls.
Read more about this here.
I hope this helps!
I feel like your life would be made a lot easier if you used async/await syntax. Just remember though that async functions return a promise. So you could instead write:
async function scenario2(ajaxCfg) {
let jqXhrResult;
try {
await callDependency();
jqXhrResult = {
jqXhr: $.ajax(ajaxCfg)
};
} catch() {
// Error handling goes here
}
return jqXhrResult;
}
I actually thought of a way easier way to do this.
You can do it by adding a method to the function constructor's prototype object. That way any created function can inherit that method and you can still use the .done() syntax. It's referred to as prototypal inheritance:
const exampleCall = { url: 'https://code.jquery.com/jquery-1.12.4.min.js'};
const depUri = { url: 'https://code.jquery.com/jquery-1.12.4.min.js'};
function callDependency() {
return $.ajax(depUri).done(() => console.log('returned callDependancy'))
}
Function.prototype.scenario2 = function(ajaxCfg, ...args) {
return this(...args).then(() => $.ajax(ajaxCfg))
}
callDependency.scenario2(exampleCall).done(data => {
console.log(data)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I want to create a function that returns an Observable.The description of the function is as follows:
The function should be delayedAlert(message:string, time:number) that returns an Observable.
The function should contain setTimeout function inside delayedAlert which prints message after the set 'time' value.
Ex:
delayedAlert(message, time){
return new Observable//how to implement setTimeout function here?
Use Observable.create to create the observable, and in the first callback, write the logic to populate the observable, which in your case is the setTimeout.
function delayedAlert(msg, time) {
return Observable.create(
observer => setTimeout(() => observer.onNext(msg), time));
}
Then to use it:
delayedAlert("Hi, Sally", 1000).subscribe(msg => alert(msg));
However, if you are using observables, you don't need to use setTimeout; use delay instead, applied to of, which creates an observable from individual value(s):
function delayedAlert(msg, time) {
return Observable.of(msg).delay(time);
}
Since it's so easy to write it this way, you probably don't need the delayedAlert function at all:
const observable = Observable.of("Hi, Sally").delay(1000);
observable.subscribe(msg => alert(msg));
I hope I didn't commit any rookie mistakes, but I can't seem to figure this one.
So here's the code:
this is a function inside a component
search(term: string,service,refArray: any[]){
service.search(term)
.subscribe(
result => {
refArray = result;
console.log(refArray); // display result as it should
console.log(this.resultArray); // display "undefined"
},
err => {
refArray = [];
console.log(err);
},
() => {console.log('completed')}
);
}
And then, I use it like this:
this.search(
searchTerm,
this.Service,
this.resultArray,
);
the problem is that my component level declared variable "apiSpots" never get the result from the subscription, even though the "refArray" parameter from the function gets it normally.
I suspect the "refArray" from inside the subscription isn't exactly the same as the one I pass to the function, but I don't know how to solve it.
Any Ideas?
EDIT: typo
SOLUTION:
So, thx to martin, here's the modified sample:
search function
search(term: string,service,callback: (result) => void){
service.search(term)
.subscribe(
result => {
callback(result);
},
err => {
callback([]);
console.log(err);
},
() => {console.log('completed')}
);
}
and usage
let context = this;
this.search(
searchTerm,
this.Service,
function(result){
context.resultArray = result;
},
);
If I understand your problem correctly you want to assign the result from service.search(term) to the refArray array passed as reference.
If you use just this:
refArray = result
Then you're overriding the local variable refArray with result but this has no effect on the reference (the original array). You just re-assigned this local variable called refArray.
You could, however, use any method that modifies the array in-place. For example call refArray.push() in a loop to append all items from the result array. Nonetheless, this isn't the best way to use Rx.
Instead return the Observable:
search(term: string,service,refrray: any[]){
return service.search(term);
}
And then subscribe to it when you need it:
this.myService.search(...).subscribe(result => this.resultArray = result);
Alternatively, if you really need to use it the way you're using it right now don't pass the refArray and use callback function instead that assigns the result to this.resultArray in local scope. Then when calling the search() method you'll just call the callback from the subscribe() call.
you have put the result values from the service to the refArray, so it is normal that it shows the values, but the resultArray is undefined, because you did passed it as the undefined. Mistake happened before calling the function.