minsu123
minsu123

Reputation: 409

Child component onClick parameter doesn't work in parent component

I set button onClick as a parameter in the child component and drag and use onClick in the parent component.

The child component Room .

type Props = {
 items?: [];
 onClick?: any; 
}

const Room = ({ onClick, items: [] }: Props) => {

  return (
  <div>
    {items.length ? (
    <>
     {items.map((item: any, index: number) => {
      return (
       <>
         <button key={index} onClick={() => { console.log('hi'); onClick }}>{item.name}</button>
       </>
   )
  }
    </>    
  )
  </div>
 )
}

This is the parent component.

const LoadingRoom = () => {

const handleWaitingRoomMove = (e: any) => {
      e.preventDefault();
      console.log('Hello Move')
    }


  return (
  <>
    <Room
     items={[
           {
              name: "Waiting Room",
              onClick: {handleWaitingRoomMove}
            },
            {
              name: "Host Room",
            },
  ]}
  >
     
    </Room>
  </> 
)
} 

I want to call parent component's onClick handleWaitingRoomMove but it's not getting called.

However, console.log('hi') on the button is called normally whenever the button is clicked. Only button is not called. Do you know why?

Upvotes: 2

Views: 85

Answers (3)

Andy
Andy

Reputation: 63524

It would probably be more advantageous to have one handler that does the work, and use that to identify each room by type (using a data attribute to identify the rooms). That way you keep your data and your component logic separate from each other. If you need to add in other functions at a later stage you can.

const { useState } = React;

function Example({ data }) {

  // Handle the room type by checking the value
  // of the `type` attribute
  function handleClick(e) {
    const { type } = e.target.dataset;
    switch (type) {
      case 'waiting': console.log('Waiting room'); break;
      case 'host': console.log('Host Room'); break;
      case 'guest': console.log('Guest Room'); break;
      default: console.log('Unknown room'); break;
    }
  }

  // Keep the room data and the handler separate
  return (
    <div>
      {data.map(obj => {
        return (
          <Room
            key={obj.id}
            data={obj}
            handleClick={handleClick}
          />
        );
      })}
    </div>
  );

}

// Apply a data attribute to the element
// you're clicking on, and just call the handler
// `onClick`
function Room({ data, handleClick }) {
  const { type, name } = data;
  return (
    <button
      data-type={type}
      onClick={handleClick}
    >{name}
    </button>
  );
}

const data = [
  { id: 1, type: 'waiting', name: 'Waiting Room' },
  { id: 2, type: 'host', name: 'Host Room' },
  { id: 3, type: 'guest', name: 'Guest Room' }  
];

ReactDOM.render(
  <Example data={data} />,
  document.getElementById('react')
);
button:not(:last-child) { margin-right: 0.25em; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>

Upvotes: 1

Jay
Jay

Reputation: 3107

You are passing onClick in items, not direct props

<button key={index} onClick={item.onClick}>{item.name}</button>

so your component will be

type Props = {
 items?: [];
}

const Room = ({ items: [] }: Props) => {

  return (
  <div>
    {items.length ? (
    <>
     {items.map((item: any, index: number) => {
      return (
       <>
         <button key={index} onClick={item.onClick}>{item.name}</button>
       </>
   )
  }
    </>    
  )
  </div>
 )
}

Upvotes: 1

Sachila Ranawaka
Sachila Ranawaka

Reputation: 41387

onlick is a attribute to the child element. so move it outside of the items array

 <Room
    
     onClick={handleWaitingRoomMove}
     items={[
           {
              name: "Waiting Room",
            },
            {
              name: "Host Room",
            },
  ]}
  >

In the child, missing () for onClick

onClick={(ev) => { console.log('hi'); onClick(ev) }}

Demo

Upvotes: 1

Related Questions