Home > Mobile >  React - How to add onClick on a button in renderBody
React - How to add onClick on a button in renderBody

Time:10-15

I am trying to implement OnClick inside the renderBody as shown in the code snippet. I need it to enable deletion of any record using it's id. I have the Table component handling table rows, data and pagination. The handleDelete function is inside the Main Component, Trials. I need to implement a call to handleDelete function for every row I want to delete.

Adding itdirectly to renderBody gives an error "undefined handleDelete..." How can I add handleDelete function on every table row dynamically inside the renderBody?

import React from 'react'

const renderBody = (item, index) => (
  <tr key={index}>
    <td>{item.sn}</td>
    <td>{item.names}</td>
    <td>{item.gender}</td>
    <td>{item.regno}</td>
    <td>{item.email}</td>
    <td>{item.phone}</td>
    <td>
      <div className='flex-action'>
        <button
          className='btn-text'
          title={`View More Information`}
          onClick={ } //how to add an onClick function here
        ><i className="bx bx-list-ol" size={30} >Delete</i>
        </button>
      </div>
    </td>
  </tr>
)

const data = [
  {
    id: 1,
    name: "IphoneX",
    img:
      "https://didongviet.vn/pub/media/catalog/product//i/p/iphone-x-mau-xam-didongviet.jpg"
  },
  {
    id: 2,
    name: "Samsung Fold",
    img:
      "https://images.samsung.com/pk/smartphones/galaxy-z-fold3-5g/buy/zfold3_carousel_mainsinglekv_mo.jpg"
  },
  {
    id: 3,
    name: "Laptop Gaming",
    img:
      "https://cdn.techzones.vn/Data/Sites/1/News/3285/techzones-nhung-mau-laptop-gaming-choi-game-co-tan-nhiet-tot-nhat-tren-thi-truong.jpg"
  }
];
const Trials = () => {

  const [users, setUsers] = useState([])

  const [products, setProducts] = useState(data);
  //You can put all product information into diaglog
  const [dialog, setDialog] = useState({
    message: "",
    isLoading: false,
    //Update
    nameProduct: ""
  });
  const idProductRef = useRef();
  const handleDialog = (message, isLoading, nameProduct) => {
    setDialog({
      message,
      isLoading,
      //Update
      nameProduct
    });
  };

  const handleDelete = (id) => {
    //Update
    const index = data.findIndex((p) => p.id === id);

    handleDialog("Are you sure you want to delete?", true, data[index].names);
    idProductRef.current = id;
  };

  const areUSureDelete = (choose) => {
    if (choose) {
      setProducts(products.filter((p) => p.id !== idProductRef.current));
      handleDialog("", false);
    } else {
      handleDialog("", false);
    }
  };
  return (
    <div className="card__body">
      {
        users.length > 0 ? (
          <Table
            limit='20'
            headData={customerTableHead}
            renderHead={(item, index) => renderHead(item, index)}
            bodyData={users}
            renderBody={(item, index) => renderBody(item, index)}
          />
        ) :
          (
            <h3>No search results</h3>
          )
      }


      {
        dialog.isLoading && (
          <Dialog
            //Update
            nameProduct={dialog.nameProduct}
            onDialog={areUSureDelete}
            message={dialog.message}
          />
        )
      }
    </div>
  )
}

export default Trials

CodePudding user response:

You can move your renderBody definition within your Trials component, so that handleDelete is within scope. Additionally, use useCallback so that renderBody doesn't have to be constructed every time you render.

import React from 'react'

const data = [ REMOVED_FOR_COMPACTNESS ];

const Trials = () => {

  const [users, setUsers] = useState([])

  const [products, setProducts] = useState(data);
  //You can put all product information into diaglog
  const [dialog, setDialog] = useState({
    message: "",
    isLoading: false,
    //Update
    nameProduct: ""
  });
  const idProductRef = useRef();
  const handleDialog = (message, isLoading, nameProduct) => {
    setDialog({
      message,
      isLoading,
      //Update
      nameProduct
    });
  };

  const handleDelete = (id) => {
    //Update
    const index = data.findIndex((p) => p.id === id);

    handleDialog("Are you sure you want to delete?", true, data[index].names);
    idProductRef.current = id;
  };

  const areUSureDelete = (choose) => {
    if (choose) {
      setProducts(products.filter((p) => p.id !== idProductRef.current));
      handleDialog("", false);
    } else {
      handleDialog("", false);
    }
  };

  // will only create the callback whenever your users state changes,
  // for performance
  // fyi renaming "item" to "user" would be clearer
  const renderBody = useCallback((item, index) => (
    <tr key={index}>
      <td>{item.sn}</td>
      <td>{item.names}</td>
      <td>{item.gender}</td>
      <td>{item.regno}</td>
      <td>{item.email}</td>
      <td>{item.phone}</td>
      <td>
        <div className='flex-action'>
          <button
            className='btn-text'
            title={`View More Information`}
            // we now have access to handleDelete, since we're defined within the componenet
            onClick={ () => handleDelete(item.id) } 
          ><i className="bx bx-list-ol" size={30} >Delete</i>
          </button>
        </div>
      </td>
    </tr>
  ), [users])

  return (
    <div className="card__body">
      {
        users.length > 0 ? (
          <Table
            limit='20'
            headData={customerTableHead}
            renderHead={(item, index) => renderHead(item, index)}
            bodyData={users}
            renderBody={renderBody}
            // you can just pass the function, like above, since it
            // already takes 2 arguments. No need for an arrow function
            // old: renderBody={(item, index) => renderBody(item, index)}
          />
        ) :
          (
            <h3>No search results</h3>
          )
      }


      {
        dialog.isLoading && (
          <Dialog
            //Update
            nameProduct={dialog.nameProduct}
            onDialog={areUSureDelete}
            message={dialog.message}
          />
        )
      }
    </div>
  )
}

export default Trials

  • Related