vivek kn
vivek kn

Reputation: 265

React - Add data to a list

I have two mapped lists of items. When I click on the div using onClick={(e) => handleCheckClick(ele)} I want to display the clicked items in a table but I am getting errors.

handleCheckClick function

 function handleCheckClick(ele) {
 if (trayItems?.length > 0) {
     settrayItems(
       trayItems.map((item) => {
         return { ...item, quantity: item.quantity + 1 };
       })
     );
   } else {
     settrayItems([...trayItems, ele]);
   }
 }

How I map two list items into div

<div>
{
    item && item.filter((person) => person.status == "0").map((ele) => {
        return (
            <div
                className="newmo-card"
                style={styles.innerbox}
                onClick={(e) => handleCheckClick(ele)}>
                {`${ele.item}`}
                <br />
                <span> {`${ele.total_price}`}</span>
            </div>

        );
    })
}
</div>
<Tray trayItems2={trayItems} trayItems1={trayPrice} /> 

Table of clicked items:

  function Tray({ trayItems }) {
    return (
      <>
      <div className="foo">
        <table>
          {trayItems &&
                trayItems.map((ele, index) => {
                  return (
                    <tr key={index}>
                      <td>{ele.item}</td>
                      <td>{ele.price}</td>
                      <td>{ele.quantity}</td>
                    </tr>
         
        </table>
      </div>
    </>
  );
}

Check the sandbox so you can identify the issue

Upvotes: 2

Views: 332

Answers (6)

Jackson Quintero
Jackson Quintero

Reputation: 188

  1. The (find) method was added to compare the id with the trayItems array, >using the selection id, inside with the (map) method, we validate again >using ternary, if it is equal it increases, if not, it is the same, now yes >selected value is not found, create a new one and add element quantity = 1

  2. method (map) was created inside to validate the selection using the >ternary is subtracted, valid up to 1, but if we click again, we delete it, >the button for the decre() function is activated by ele.quantity

https://codesandbox.io/s/fast-currying-nfmxfm?file=/src/App.js

  export default function App() {
      const [trayItems, settrayItems] = useState([]);
     
  
    // 1.
  const handleCheckClick = (ele) => {
    const dupe = trayItems.find((obj) => obj.user_id === ele.user_id);

    settrayItems(
      dupe
        ? trayItems.map((stat) =>
            stat.user_id === ele.user_id
              ? { ...stat, quantity: stat.quantity + 1 }
              : stat
          )
        : [...trayItems, { ...ele, quantity: (ele.quantity = 1) }]
    );
  };
   

  // 2.
const decre = (idd) => {
    settrayItems(
      trayItems.map((stat) =>
        stat.user_id === idd
          ? stat.quantity !== 1
            ? {
                ...stat,
                quantity:
                  stat.quantity > 1 ? stat.quantity - 1 : (stat.quantity = 1)
              }
            : trayItems.filter((e) => e.id !== idd)
          : stat
      )
    );
  };

  function Tray({ trayItems }) {
    return (
      <>
        <div className="foo">
          <table>
            <tbody>
              {trayItems &&
                trayItems.map((ele, index) => {
                  return (
                    <tr key={index}>
                      <td>{ele.item}</td>
                      <td>{ele.price}</td>
                      <td onClick={() => decre(ele.user_id)>{ele.quantity}</td>
              
                    </tr>
                  );
                })}
            </tbody>
          </table>
        </div>
      </>
    );
  }

  return (
    <>
      <div>
        {item &&
          item
            .filter((person) => person.status === 0)
            .map((ele, index) => {
              return (
                <div
                  style={{ cursor: "pointer" }}
                  key={index}
                  className="newmo-card"
                  onClick={() => handleCheckClick(ele)}
                >
                  {`${ele.item}`}
                  <br />
                  <br />
                  <span> {`${ele.price}`}</span>
                </div>
              );
            })}
      </div>
      <Tray trayItems={trayItems} />
    </>
  );
}

Upvotes: 0

Savaj Patel
Savaj Patel

Reputation: 535

There is something issue that in your code

handleCheckClick function

const handleCheckClick = (ele) => {
let index = trayItems.findIndex((item) => item.user_id === ele.user_id);
if (index >= 0) {
  let newItems = trayItems;
  let item = trayItems.find((item) => item.user_id === ele.user_id);
  item = { ...item, quantity: item.quantity + 1 };

  newItems.splice(index, 1, item);

  settrayItems([...newItems]);
} else {
  settrayItems([...trayItems, ele]);
}
};

For more details Check the sandbox

Upvotes: 0

IAmRC1
IAmRC1

Reputation: 121

The issue in your code was how you handled the click function and the modification of state subsequently.

  1. Removed duplicate products (having same id)
const items = [
  {
    user_id: 1,
    item: "biriani",
    price: "50",
    selling_price: "60",
    created_at: "2022-08-29T10:12:58.000000Z",
    updated_at: "2022-09-15T14:05:45.000000Z",
    tax: "5%",
    total_price: "80",
    status: 0,
    quantity: 0
  },
  {
    user_id: 2,
    item: "burger",
    price: "80",
    selling_price: "80",
    created_at: "2022-08-29T10:21:13.000000Z",
    updated_at: "2022-09-14T04:46:36.000000Z",
    tax: "5%",
    total_price: "100",
    status: 0,
    quantity: 0
  },
  {
    user_id: 3,
    item: "alfarm",
    price: "100",
    selling_price: "120",
    created_at: "2022-09-07T11:06:23.000000Z",
    updated_at: "2022-09-07T11:06:23.000000Z",
    tax: "5%",
    total_price: "140",
    status: 0,
    quantity: 0
  },
  {
    user_id: 4,
    item: "sandwich",
    price: "100",
    selling_price: "120",
    created_at: "2022-09-07T13:27:33.000000Z",
    updated_at: "2022-09-14T04:46:37.000000Z",
    tax: "5",
    total_price: "140",
    status: 0,
    quantity: 0
  },
  {
    user_id: 5,
    item: "pizza",
    price: "200",
    selling_price: "220",
    created_at: "2022-09-07T13:27:33.000000Z",
    updated_at: "2022-09-07T13:27:33.000000Z",
    tax: "5",
    total_price: "240",
    status: 0,
    quantity: 0
  },
  {
    user_id: 6,
    item: "chicken sadwich",
    price: "200",
    selling_price: "220",
    created_at: "2022-09-07T13:27:33.000000Z",
    updated_at: "2022-09-07T13:27:33.000000Z",
    tax: "5",
    total_price: "250",
    status: 0,
    quantity: 0
  },
  {
    user_id: 7,
    item: "sharja shake",
    price: "60",
    selling_price: "70",
    created_at: "2022-09-09T06:58:45.000000Z",
    updated_at: "2022-09-15T14:05:53.000000Z",
    tax: "5%",
    total_price: "80",
    status: 0,
    quantity: 0
  }
];
  1. Kept single variable in state for products & updated state accordingly
export default function App() {
  const [trayItems, setTrayItems] = useState([]);

  const handleCheckClick = (item) => {
    const itemExists = trayItems.findIndex((ite) => ite.user_id === item.user_id) !== -1;
    if (itemExists) {
      setTrayItems(
        trayItems.map((prod) => ({
          ...prod,
          quantity:
            prod.user_id === item.user_id ? prod.quantity + 1 : prod.quantity
        }))
      );
    } else {
      setTrayItems([...trayItems, { ...item, quantity: item.quantity + 1 }]);
    }
  };

  return (
    <>
      <table>
        {items
          ?.filter((item) => item.status === 0)
          ?.map((item, index) => {
            return (
              <tbody
                key={index}
                onClick={() => handleCheckClick(item)}
              >
                <td>{item.item}</td>
                <td>{item.total_price}</td>
              </tbody>
            );
          })}
      </table>
      <Tray trayItems={trayItems} />
    </>
  );
}
  1. Moved the child component outside parent.
const Tray = ({ trayItems }) => {
  return (
    <table>
      <tbody>
          {trayItems?.map((ele, index) => (
            <tr key={index}>
              <td>{ele.item}</td>
              <td>{ele.price}</td>
              <td>{ele.quantity}</td>
            </tr>
          ))}
      </tbody>
    </table>
  );
};

Upvotes: 0

nullptr
nullptr

Reputation: 4474

I'm sharing the significant parts of the code here. Check the code sandbox for the working code.

Here are the significant changes:

  1. Moved the Tray definition outside the App component. Defining a component inside another component is almost always a bad idea. You won't have an issue because you don't have any state in Tray. If you had any state, it would have been reset to the initial value on every render of App.
  2. Changed the trayItems to an object. The keys are the ids of each item. And the value is an object that contains the name, quantity, and price.
  3. We'll only render the item in the Tray if the quantity is greater than 0.
  4. Changed the handleCheckClick to handle the object.
function Tray({ trayItems }) {
  return (
    <>
      <div className="foo">
        <table>
          <tbody>
            {Object.entries(trayItems)
              .filter(([, v]) => v.quantity > 0)
              .map(([k, v]) => {
                return (
                  <tr key={k}>
                    <td>{v.item}</td>
                    <td>{v.price}</td>
                    <td>{v.quantity}</td>
                  </tr>
                );
              })}
          </tbody>
        </table>
      </div>
    </>
  );
}

export default function App() {
  const [trayItems, setTrayItems] = useState(
    item.reduce((prev, curr) => {
      return {
        ...prev,
        [curr.user_id]: { item: curr.item, quantity: 0, price: curr.price }
      };
    }, {})
  );

  const handleCheckClick = (ele) => {
    setTrayItems((prev) => {
      return {
        ...prev,
        [ele.user_id]: {
          ...prev[ele.user_id],
          quantity: prev[ele.user_id].quantity + 1
        }
      };
    });
  };

  return (
    <>
      <div>
        {item &&
          item
            .filter((person) => person.status === 0)
            .map((ele, index) => {
              return (
                <div
                  key={index}
                  className="newmo-card"
                  onClick={() => handleCheckClick(ele)}
                >
                  {`${ele.item}`}
                  <br />
                  <span> {`${ele.total_price}`}</span>
                </div>
              );
            })}
      </div>
      <Tray trayItems={trayItems} />
    </>
  );

Edit intelligent-brahmagupta-qchf18

Upvotes: 1

Kanti vekariya
Kanti vekariya

Reputation: 697

here why do you manage two diff states? pls check the working demo here.

import { Fragment, useState } from "react";
import "./styles.css";
const item = [
  {
    user_id: 1,
    item: "biriani",
    price: "50",
    selling_price: "60",
    created_at: "2022-08-29T10:12:58.000000Z",
    updated_at: "2022-09-15T06:17:20.000000Z",
    tax: "5%",
    total_price: "80",
    status: 1,
    quantity: 0

  },
  {
    user_id: 5,
    item: "alfarm",
    price: "100",
    selling_price: "120",
    created_at: "2022-09-07T11:06:23.000000Z",
    updated_at: "2022-09-07T11:06:23.000000Z",
    tax: "5%",
    total_price: "140",
    status: 0,
    quantity: 0
  }
];
export default function App() {
  const [trayItems, settrayItems] = useState([]);

  const handleCheckClick = (ele) => {
    if (trayItems?.length > 0) {
      settrayItems(trayItems.map((item) => {
        return { ...item, quantity: item.quantity + 1 };
      }))
    } else {
      settrayItems([...trayItems, ele]);
    }
  };

  function Tray({ trayItems }) {
    return (
      <>
        <div className="foo">
          <table>
            <tbody>
              {trayItems &&
                trayItems.map((ele, index) => {
                  return (
                    <tr key={index}>
                      <td>{ele.item}</td>
                      <td>{ele.price}</td>
                    </tr>
                  );
                })}
            </tbody>
          </table>
        </div>
      </>
    );
  }

  return (
    <>
      <div>
        {item &&
          item
            .filter((person) => person.status === 0)
            .map((ele, index) => {
              return (
                <div
                  key={index}
                  className="newmo-card"
                  onClick={() => handleCheckClick(ele)}
                >
                  {`${ele.item}`}
                  <br />
                  <span> {`${ele.total_price}`}</span>
                </div>
              );
            })}
      </div>
      <Tray trayItems={trayItems} />
    </>
  );
}


Upvotes: 0

Huy Pham
Huy Pham

Reputation: 449

There is a warning that <td> and <tr> cannot appear as a child of <table>.

Wrap body with <body> tag and use <tr> tag to represent each row.

<div className="foo">
  <table>
    <tbody>
      {trayItems2.length === trayItems1.length &&
        trayItems2.map((ele, index) => {
          return (
            <tr key={ele}>
              <td>{ele}</td>
              <td>{trayItems1[index]}</td>
            </tr>
          );
        })}
    </tbody>
  </table>
</div>

Because of using trayItems1[index] to get map items in another array so you need to pre-check them. You need to refine it for tighter conditions.

Also, define unique key props for each child element in <table>. Here I simply use key={ele}. And using two arrays is redundant. Merge them could be easier.

Upvotes: 0

Related Questions