I'm trying to understand how the "event" object is passed and recovered between functions.
It was my understanding that event is passed by default as an argument and after seeing the example below it's confusing me even more how this works.
How "...args" is getting the event object?
const MyInput = document.querySelector('input');
const checkActivity=(f1)=>{
return (...args)=>{
console.log(args);
f1(args);
};
}
const MyFunc=(e)=>{
console.log(e);
};
MyInput.addEventListener('input',checkActivity(MyFunc));
Here, checkActivity(MyFunc) is being executed before adding the event listener and not used as a callback. It's the result of this call that is used as a callback. Callback that accepts (...args) possibly an event.
How "...args" is getting the event object?
Let's take that last line of code and possibly make it a bit clearer:
const inputHandler = checkActivity(MyFunc);
MyInput.addEventListener('input', inputHandler);
checkActivity creates a function that it returns, which I've called inputHandler above. That function is:
(...args) => {
console.log(args);
f1(args);
};
The ...args in the parameter list of the function is a rest parameter. It says "take all the arguments this function was called with and gather them up into an array." So args is an array of the arguments the function was called with.
A function attached as an event listener with addEventListener like inputHandler is gets called with just one argument: the event object for the event. So in inputHandler, args[0] is the event object.
Related
const mapDispatchToProps = dispatch => {
return {
buyCake: () => dispatch(buyCake())
}
}
When I run my program by changing the third line to
buyCake: dispatch(buyCake())
it doesn't work. What is the difference between these two approaches and why do you need the () =>
buyCake: () => dispatch(buyCake())
This will declare buyCake to be a function that takes no arguments, and calls dispatch in its body; but buyCake itself won't be called until you explicitly call it.
It's more or less conceptually equivalent to:
function buyCake() {
dispatch(buyCake());
}
I say conceptually because there are some technical differences between regular functions and arrow functions (a.k.a. lambdas, lambda expressions); see this for more info.
On the other hand
buyCake: dispatch(buyCake())
will set buyCake to the result of the call to dispatch (dispatch will be called immediately, right there).
It's the same as the difference between:
const getSinPI = () => Math.sin(Math.PI); // a function named `getSinPI`
getSinPI(); // returns approx. 0
and
const sinPI = Math.sin(Math.PI); // a variable storing the result (approx. 0)
The mapDispatchToProps function returns an object containing, as properties, ad-hoc wrapper functions that you defined, that perform calls to dispatch in some way that makes sense for your application. This object is then used to place these functions on the props object (the different dispatch calls are "mapped" onto these wrappers - thus the name). This is so that you can make use of dispatch in a more convenient way, using wrapper functions with names that more closely reflect what your application is doing.
Consider this function:
export const catchAsync = (handler) =>
(...args) =>
^^^^ why are these the parameters to handler, and not catchAsync?
handler(...args).catch(args[2]);
In the first returned function, it says:
(...args: [Request, Response, NextFunction]) =>
Now, to my knowledge, ...args would be exactly one thing: 'handler' It wouldn't be the parameters to the callback because those aren't the arguments to catchAsync, they are the arguments to the callback function 'handler'. Is there something I didn't learn about arguments of a callback being passed to the original function?
Thanks!
catchAsync is a function which returns another function. The outer function and the inner function each get passed different things. You would use this code something like the following:
const handlerWithCatch = catchAsync(someHandlerFn);
handlerWithCatch(someRequest, someResponse, someNextFn);
// Or on a single line:
catchAsync(someHandlerFn)(someRequest, someResponse, someNextFn)
On the insider handler will contain someHandlerFn, and args will be an array of [someRequest, someResponse, someNextFn]
Just re-read your question 1000 times.
As you mention ...args is not the argument of catchAsync. This function is how you implement the Strategy design pattern in Javascript.
catchAsync itself will return a function that you will call with req,res,next
catchAsync(handler)(req,res,next);
I have callback in interface:
interface {
onLoad?: () => void;
}
I tried to catch this callback using this:
props.onLoad(() => this.mapLoaded = true);
But I get this error:
Expected 0 arguments, but got 1.
It's hard to say for certain without more context, but you're probably meant to assign to onLoad rather than call it:
props.onLoad = () => this.mapLoaded = true;
Typically, a callback is called by the object you're passing the interface to, so that it can call back to your code when something happens (in this case, presumably when a map is loaded).
I've been going through several JavaScript concepts now, including a several react conveys, and there's a couple of questions that I am wondering and wishing to get help from you guys.
Suppose we have a function name sum:
const sum = (a,b) => a + b
Question 1:
I've seen a lot of anonymous functions being called to call another function, I am wondering the reason why we do that instead of calling that specific function directly. For example:
Instead of using
onClick = {sum}
we use:
onClick ={() => sum}
Also, in the react course, I am wondering why do we call mapDispatchToProps like:
Increment: () => dispatch({type: 'INCREMENT'})
but not:
increment: dispatch({type: 'INCREMENT'})
Question 2:
When do we use sum() or sum in the click event, for example:
onClick = {sum()} OR onClick = {sum}
Question 3:
As we know that Redux-Saga implements generator function, but as from what I know, generator function when it has more than one yield, it requires next() in order to go on.
However, in Redux-Saga, I don't see the use of next(), is that because the Sagas has already automatically called next() in it's function?
Thanks guys. Much appreciated!
For the question 1 and 2, the onClick property expects a event handler (which is a function definition) that has the event as the first parameter and should not return anything.
When the button is clicked, the onClick function invokes, passing the event as the first argument.
Read more at Handling Events in React
const sum = (a, b) => a + b
// an `event` will be passed as the first argument, the second argument gets undefined
onClick={sum}
// you could opt out the `event` parameter and call `sum` with your arguments
onClick={() => { sum(5, 10) }}
onClick={() => sum(5, 10)} // this will return the value of `sum(5, 10)` to the caller of onClick, which is not useful since the caller don't expect that
=> Using anonymous callback gives you the ability to call the function with specific arguments
// invalid usages, calling the function immediately which will assign the returned value to `onClick`, and the that returned value is not a function definition
onClick={sum(5, 10)}
increment: dispatch({type: 'INCREMENT'})
For the question 3, redux-saga acts as a generator runner that has handled calling next() for you. You only need to define the generator function (in combination with using their redux-saga effects)
If I call the function once like this
var button = document.querySelector('button');
button.addEventListener('click', once);
function once() {
console.log('one');
button.removeEventListener('click', once);
}
It's calling only once.
But if I called like this once()
var button = document.querySelector('button');
button.addEventListener('click', once());
function once() {
console.log('one');
button.removeEventListener('click', once());
}
Exception throws
Exception: InternalError: too much recursion
Could you please explain why this is happening.
() after function name invoke's the function. So as button.addEventListener('click', once()); you are bind the return value of once() method which is undefined.
And since once() is called recursively without any break statement, you are getting the InternalError: too much recursion.
You should pass the function reference.
button.addEventListener('click', once);
For Additional Info:
Pointer Vs Delegates
If you put () after the name of a variable holding a function, then you call the function.
If a function calls itself, then it will get called, call itself, call itself again and so on unto infinity. This is recursion. Doing something unto infinity will cause a computer to run out of memory, so it is undesirable.
JavaScript engines prevent this by throwing an exception when you try it.
(There are exceptions, of course, a function that calls itself conditionally can be very useful).
The first code is correct, because you register the function to be called.
The second code tries to register the result of the function call once(). This means you actually execute the function when you only want to register it. Now, in your function body, you do the same to deregister the callback. Here again, you call the function you are already executing and hence, you recurse infinitely.