Home > Software engineering >  Child component onClick parameter doesn't work in parent component
Child component onClick parameter doesn't work in parent component

Time:12-22

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?

CodePudding user response:

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

CodePudding user response:

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>
 )
}

CodePudding user response:

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>

  • Related