I am creating a modal. This modal will be opened when any of 6 div
elements are clicked. Each of the components are created using the .map()
function to an array. The popup
parameter is supposed to be the function that runs when clicked:
items.map(item => (
<StoreItem popup={() => popup} item={item} />
))
For each item
from items
, there is a StoreItem
created. Here is the code for the StoreItem
component:
const StoreItem = ({popup, item}) => {
return (
<div onClick={popup(item)} className="...">
...
</div>
);
};
As seen above, each StoreItem
is a div
with an onClick
property that runs the popup()
function. Here's the popup()
function:
function popup(item) {
console.log(item);
}
For some reason, when I console.log(item)
, the item
that is supposed to be passed in from the onClick
is not being logged. Rather, I'm getting a SyntheticBaseEvent
with random stuff that I don't want.
How is this fixed so that the contents of item
are properly displayed, not some SyntheticBaseEvent
?
Thanks, any help is appreciated.
To make it work, you should shake parentheses a little:
// No parentheses here in the popup props
items.map(item => (
<StoreItem popup={popup} item={item} />
))
const StoreItem = ({popup, item}) => {
// But create a new arrow function here
return (
<div onClick={() => popup(item)} className="...">
...
</div>
);
};
This is not a react-specific question, this is how functions work in JavaScript. Let me explain some details
How to call a function
So, you created a function
function popup(item) {
console.log(item);
}
To make it log something, we should call the function and pass something as a parameter, like that:
popup("hello")
The code above logs "hello"
, because we called the function (write parentheses after the function name) and passed the "hello"
string as a parameter to it.
But when you do not write the parentheses after its name, you can treat the function as a variable. For example, you may assign a function to a new variable:
const meow = popup
popup("hello") // it logs "hello"
meow("hello") // it logs "hello", because it calls the same function, just by a different name
Let’s see how your code works
Take a look at the code where you render items
items.map(item => (
<StoreItem popup={() => popup} item={item} />
))
Here you create a new arrow function () => popup
. The function does not take any parameters (its’ parentheses are empty), and returns the popup
function. But again, it does not call the popup
function, right? Because we don’t see any parentheses after the word popup
.
Then, when rendering a single item, you do not create a new function, but call what you get as the popup property:
const StoreItem = ({popup, item}) => {
return (
<div onClick={popup(item)} className="...">
...
</div>
);
};
So, in the popup
property you get the function you created in the parent component, right:
() => popup
And now, when passing to the onClick
property, you finally call it:
onClick={popup(item)}
Right? So you call the () => popup
with item
as a parameter. But the () => popup
function does not take any parameter. But it returns your original function popup
. So, the code is equivalent to the following:
onClick={function popup(x) {
console.log(x);
}}
As you may see, the function takes one parameter and has no idea about your "item" variable. I intentionally named it "x" to show that the name of the variable does not matter. The function just logs what its parameter is, not some outer-scope variable.
So, when you click on the element, react captures the event and passes the event to your function.
If you’d like to understand this topic more deeply, you may read something on "higher-order functions" topic.