How does react know to provide the event as a second argument in the code below?
const clickMe = (parameter) => (event) => {
event.preventDefault();
// Do something
}
<button onClick={clickMe(someParameter)} />
Does it generate this to:
<button onClick={(event) => clickMe(someParameter)(event)} />
Or how does it work?
Thanks.
Maybe this will help explain it a little better.
Closures are functions that carry the information (variables etc.) from their local environment with them when they're returned.
I'll work this example without arrow functions as they can be a little deceiving.
// `multplyBy` accepts a number as its argument
// It returns a new function that "remembers" that number
// when it's returned. But that new function *also*
// accepts a number
function multiplyBy(n) {
return function(n2) {
return n2 * n;
}
}
// So `multiplyBy(5)` returns a new function
// which we assign to the variable `five`
const five = multiplyBy(5);
// And when we call `five` with a number we get
// the result of calling 5 * 10.
console.log(five(10));
If you substitute multiplyBy(n) with clickMe(n) you'll see that you'll get a new function that gets used by the click listener, and the first argument of that function will always be the event.
Clickme variable in your code is a function which has return is function e => {...}. So when you specify like this:
<button onClick={clickMe(someParameter)} />
it is equivalent to
<button onClick={e => {...} />
which is basic form of a event handler in react
Related
The question seems simple, but it doesn't work for me :(
I am adding listeners depending on the conditions.
If the first condition is true, I add a function
ref.current.onclick = ()=> {function1()}
If the second condition is true, I add the second function
ref.current.onclick = ()=> {function2()}
This removes the first function. How to add a second function without deleting the first?
I tried:
ref.current.onclick = ()=> {ref.current.onclick, function2()}
ref.current.onclick = ()=> {ref.current.onclick(), function2()}
ref.current.onclick = ()=> {()=>ref.current.onclick(), function2()}
This does not work
Something in my question confuses readers)
I have no problem with conditions.
I can't add a second function to the onClick event without removing the first one.
You could use a conditional (ternary) operator like this:
{YourCondition ? ref.current.onclick = ()=> {function1()} : ref.current.onclick = ()=> {function2()}}
For more informations, click on this link to see the full documentation about conditional rendering, which will help you.
I wasn't able to communicate this point clearly in the comments, so here is an example. Without more context of your problem (what is your "condition"?) it is hard to know if this solves your problem or not. Hope it helps though.
Below is a react component that has conditional behavior when you click "Process Number".
If the number is odd, function A gets called.
If the number is even, function B gets called.
But, the onClick function is always the same: "processNumber"
The key concept here is the processNumber function that is able to handle the condition and call A or B accordingly. You could add all kinds of logic in here, but the onClick would always point to processNumber, not some other function.
//EvenOddComponent.js
import { useState } from 'react';
export default function EvenOddComponent() {
const [number, setNumber] = useState(1)
function A() {
console.log('the number is odd')
}
function B() {
console.log('the number is even')
}
function processNumber() {
if (number % 2 != 0) {
A()
} else {
B()
}
}
return <div>
<>{number}</>
<button onClick={() => setNumber(number + 1)}>Increment Number</button>
<button onClick={processNumber}>Process Number</button>
</div>
}
An alternative solution could be to pass the onClick function in as a prop like this:
export default function funcCaller(props) {
return <button onClick={props.functionToCall}>Do thing</button>
}
Why does onClick={props.onClickFunction(1)}> doest not work ?
Function Button(props) {
// const handleClick = () => setCounter(counter+1);
return (
<button onClick={props.onClickFunction(1)}>
+{props.increment}
</button>
}
Why should I use another function
`
function Button(props) {
const handleClick = () => props.onClickFunction(1)
return (
<button onClick={handleClick}>
+{props.increment}
</button>
);
}
`
When I tried declaring handleclick function it's working .
The difference is perhaps best illustrated by the snippet below, which shows what you're effectively doing in each of your examples.
// top example
handleClick = () => props.onClickFunction(1)
// bottom example
handleClick = props.onClickFunction(1)
You are assigning the result of calling the onClickFunction by mistake, when what you actually want to do is assign a function that calls onClickFunction each time it's called. The following code will also work as intended:
function Button(props) {
return (
<button onClick={() => props.onClickFunction(1)}>
+{props.increment}
</button>
}
When a component renders, all statements are executed and expressions are evaluated.When Component renders props.onClickFunction(1) function is called which returns undefined which will cause the button to render as causing nothing to occur.
handleClick on the other hand is a reference to a function. You need to pass the function reference to onClick and later when the click happens , it can be called later by React.
"Click" is an event so you have to pass an event handler function. When click is detected on the element that handler function will run.
// you are passing an event handler
<button onClick={handleClick}>
But in this case onClick={props.onClickFunction(1)}, you are passing the return value of props.onClickFunction function and if this function does ont return anything, its return value will be undefined.
I have the following codes:
class Autocomplete {
constructor(ele, options) {
this.ele = ele;
this.options = options;
this.input = this.ele.querySelector('.input');
// with keyup we want to fire it right away
// this.input.addEventListener('keyup', (e) => this.display(e);
}
}
The display function will then display the user's input onto the page. However, I wonder what the difference is between these 3 functions:
1)
this.input.addEventListener('keyup', (e) => this.display(e));
this.input.addEventListener('keyup', this.display);
this.input.addEventListener('keyup', () => this.display());
Only function 1 and 2 work, and to my understanding, function 1 will put e as argument into the display function whereas function 2 will execute immediately on keyup. However, for 3, why does it not work, because I thought the e argument is passed in implicitly by the DOM API?
Out of the first 2 functions, which one is more performant and why?
Arrow function is not bound to the class where it is declared when it is called, you should use function only if you want to use the this in the function because in the arrow function, it's the global this that is get called
With a typical react function, calling the function within an event (e.g. onClick={}) will result in the function being called immediately upon component mount.
For example, this code will fire immediately upon mount because the function is being called:
const App = () => {
const fn = () => {
alert("hey");
};
return (
<button onClick={fn()}>click</button>
);
};
However, if the function uses a closure, it will only execute when the button is clicked. For example:
const App = () => {
const fn = () => {
return () => alert("hey");
};
return (
<button onClick={fn()}>click</button>
);
};
Why does this occur?
To understand what's going on here it might help to substitute the function call with what it's evaluating to (inlining the call). In the first case, it is undefined, as the function does not return anything. While evaluating it's value, it also alerts, resulting in:
alert("hey"); // this is more or less executed here
<button onClick={undefined} >
In the second case, the function returns another function, so that's what it evaluates to:
<button onClick={() => alert("hey")} >
Now a function get's passed to onClick, which will be called when the button is actually clicked.
I have trouble with TypeScript/JavaScript
I have an array of function like this
private listeners: ((name: string) => void)[] = [];
I'm adding functions to it in another function that seems to work.
now I want to call those functions if a button is pressed
button.onclick = function(){
this.listeners.forEach((callback) => callback(username));
}
if I try my code this way nothing happens, I bet it is because it doesn't know listeners.
my next try was
button.onclick = function(listeners){
listeners.forEach((callback) => callback(username));
}
Now tsc tells me
error TS2339: Property 'forEach' does not exist on type 'MouseEvent'.
I bet I'm missing a type here, but idk how to tell him that this array is an array of functions of type ((name: string) => void)[] = [];
Would be cool if someone knows a quick workaround.
Before you ask: I'm sure that my function added functions to my array (at least in the add function the size of listerns got bigger) :D
Try to define your onclick handler like this to keep 'this' pointing to the current class instance:
private onClick(ev)
{
this.listeners.forEach((callback) => callback(username));
}
//Then somewhere later
button.onclick = (ev) => this.onClick(ev);
Your main problem is that this doesn't refer to your expected context. Instead, this refers to the MouseEvent context of your click handler.
As a simple solution for your problem you might use Function.prototype.bind().
Change
button.onclick = function(){
this.listeners.forEach((callback) => callback(username));
}
To this
button.onclick = function(){
this.listeners.forEach((callback) => callback(username));
}.bind(this);
Basic explanation:
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
A more sophisticated way of dealing with your issue is not to use onclick at all, but rather addEventListener, and you can use the following little-known approach of passing an object with a handleEvent method to addEventListener, which makes all your issues with this moot:
class Foo {
private listeners: ((name: string) => void)[] = [];
constructor(button) {
button.addEventListener('click', this);
}
handleEvent(event) {
// check event type
this.listeners.forEach(callback => callback(username));
}
}
const new Foo(document.getElementById('myButton'));
Thanks for the awnsers
i guess that a direct add of a function wont work because its an Eventhandler function, which works somewhere in the code but not there where i defined it.
I changed to addeventhandler and defined with let a function inside my function, and call a new function for the Eventhandler which calls the function it should call.#funcception :D
let triggerOnClick = () => {
let username = tf_name.value;
this.listeners.forEach((callback) => callback(username));
};
btn_enter.addEventListener("click", () => {
triggerOnClick();
});
that code works :)