skip to Main Content

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.

2

Answers


  1. 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.

    Login or Signup to reply.
  2. React is passing the event object to your function, you can’t control that by naming the parameter something else.

    What you want to do is pass an anonymous function to onClick, in which you call popup(item).

    <div onClick={() => popup(item)} className="...">
    

    What’s happening is that React will still pass the event object to the function, but you ignore that by not including it in your function definition. then in the body of the function, execute your on logic, namely, calling the popup function with the item.

    This is what is happening, notice that you do nothing with the event, but it is going to be the first parameter of that function, regardless.

    <div onClick={(event: SyntheticBaseEvent) => popup(item)} className="...">
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search