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)
Related
I've recently stumbled upon code (below) using the ES6 rest parameter and there is something that I cannot fully grap:
--> it's a debounce function that is used to limit the number of API calls when the user types in an input field.
--> the debounce function takes in a callback function and a delay param (which is set to 250 by default).
--> the debounce function uses a wrapper for the callback to make sure it is called only after a delay. The callback function is called in the wrapper with the arguments passed to updateDebounceText.
I understand the code and the overall logic, but what trips me out is how can the wrapper in the debounce function have access to the ...args of the callback? I know that a child function can directly access the rest parameter of the parent function, but in this case, the parent function accesses the rest parameter of the callback.
I'm sure the answer is pretty simple but I can't 100% grasp for now! any help would appreciated!
thanks a lot!
function debounce(cb, delay = 250) {
let timeout
return (...args) => {
clearTimeout(timeout)
timeout = setTimeout(() => {
cb(...args)
}, delay)
}
}
const updateDebounceText = debounce((text) => {
console.log(text)
})
input.addEventListener("input", (e) => {
updateDebounceText(e.target.value);
})
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.
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.
I have a question about asynchronous/synchronous when we write code in JS and I have done google search but I am still a bit confused.
I understand that we use callback functions when we want to make sure that the callback function is executed only after the asynchronous task (such as accessing database) in the outer function is complete. I understand how deserialize and serialize user works.
I am confused why when we do serialize user or deserialize user with passport.js we need a callback function like this ?
passport.serializeUser((user, done) => {
done(null, user.id);
});
If all we want is that the inner arrow function that is passed as an argument to serializeUser() to be executed only after serializeUser() is finished. Or why do we need to pass it as a callback function instead of calling that arrow function below serializeUser() ? I thought JS is synchronous so it will execute the arrow function after serializeUser() is completed anyway ?
I only found serializeUser() documentation in passport documentation on how to use it, but not its implementation so I am also confused whether serializeUser() or deserializeUser()( or any other passport functions) are asynchronous functions ?
Thank you !
It is a fragment of this function on github (https://github.com/jaredhanson/passport/blob/08f57c2e3086955f06f42d9ac7ad466d1f10019c/lib/authenticator.js).
As you can see this function takes a fn parameter. Then it checks if it is a function. If yes it pushes it to this._serializers. Later it does 'some magic' on it, I think it's not important now.
As you can read in jsdoc, serializeUser purpose is to register a function used to serialize user objects. So you pass some function which is invoked later in a code with 2 arguments which labels on that particular function level are user and done.
They left you some space which you can fill with your own code. You can tell how this will behave. They gave you an opportunity to implement your own logic.
Simple example:
function doSomeMagic(fn) {
// I do some my staff
const a = 5;
const b = 10;
// and now I let you decide what to do
// you can implement your own logic in my function
const result = fn(a, b);
console.log(result);
}
doSomeMagic((a, b) => {
return a * b;
});
doSomeMagic((a, b) => {
return a + b;
});
//output:
// 50
// 15
That's exactly what they've done. You can take my function, I give you two arguments do whatever you want. You can multiply, add, substract, whatever you want. I don't have to write separated functions to do math, I can write one, pass values as arguments and let you decided what operation you want to do. And it doesn't mean my code is going to run in an async way.
I have:
this.selectedItem.subscribe(model => {
this.currentEditor(this.editors.find(e => e.canRender(model)));
this.currentEditor().render(model);
});
where this.selectedItem already has a value.
Is it possible to run callback (but leaving it anonymous) immediately after subscribing?
You can call valueHasMutated on this.selectedItem, so
this.selectedItem.valueHasMutated()
However this not just runs your callback but also notify everybody else, e.g bindings, computeds etc.
So you are propably better to have a named function and call it when it is needed and use that also in the subscribe.
You can extract function into a variable and call it:
var changeHandler = (model) => {
this.currentEditor(this.editors.find(e => e.canRender(model)));
this.currentEditor().render(model);
};
this.selectedItem.subscribe(changeHandler);
changeHandler();