0

I am trying to implement a delete button to remove a row from the table inside a modal using Ant Design UI library. However, whenever I call the remove function, even if I have previously added several new items on top of the initial items, the data state usage inside the removeItem component is not updated and always uses the initial version. Whenever I output the data state from inside the removeItem component, it always shows the 3 items from the beginning.

But the weird thing is if I output the data content from inside the addItem component or useEffect hook, it shows the added new rows. I cannot figure out where the issue lies.

Edit: link to codesandbox (edit barang -> add some new items -> remove new item -> see console log) https://codesandbox.io/embed/wispy-meadow-czv6p?file=/src/App.js&codemirror=1

import { useState, useEffect } from "react";

const ModalBarang = (props) => {
  const dataSource = [
    {
      key: 1,
      code: "A123",
      name: "Barang 1",
      desc: "Description 1",
      qty: 30,
      price: 10000,
      total: 30 * 10000,
    },
    {
      key: 2,
      code: "B123",
      name: "Barang 2",
      desc: "Description 2",
      qty: 10,
      price: 20000,
      total: 10 * 20000,
    },
    {
      key: 3,
      code: "B123",
      name: "Barang 2",
      desc: "Description 2",
      qty: 10,
      price: 20000,
      total: 10 * 20000,
    },
  ];

  const tableColumns = [
    {
      title: "No",
      dataIndex: "key",
    },
    {
      title: "Kode Barang",
      dataIndex: "code",
      render: (text, _) => {
        return <Input value={text} />;
      },
    },
    {
      title: "Nama Barang",
      dataIndex: "name",
      render: (text, _) => {
        return <Input value={text} />;
      },
    },
    {
      title: "Deskripsi",
      dataIndex: "desc",
      render: (text, _) => {
        return <Input value={text} />;
      },
    },
    {
      title: "Qty",
      dataIndex: "qty",
      render: (text, _) => {
        return <Input value={text} />;
      },
    },
    {
      title: "Harga",
      dataIndex: "price",
      render: (text, _) => {
        return <Input value={text} />;
      },
    },
    {
      title: "Total",
      dataIndex: "total",
    },
    {
      title: "Hapus",
      dataIndex: "remove",
      render: (_, record) => {
        return (
          <Button
            type="default"
            danger="true"
            onClick={() => removeItem(record.key)}
          >
            Hapus Barang
          </Button>
        );
      },
    },
  ];

  const [columns, setColumns] = useState(tableColumns);
  const [data, setData] = useState(dataSource);

  const addItem = () => {
    const newRow = {
      key: data.length + 1,
      code: "",
      name: "",
      desc: "",
      qty: 0,
      price: 0,
      total: 0,
    };

    const newData = [...data, newRow];

    setData(newData);
  };

  const removeItem = (key) => {
    console.log(data); // ----> even after adding several items (addItem) the log only shows the initial values just like in datasource. E.g. initial items = 3, addItems 2 times so there should be 5 items. But when trying to remove item using this component, this console log only outputs the 3 initial items.

    const newItems = data.filter((item) => item.key !== key);

    setData(newItems);
  };

  return (
    <Modal
      title="Barang"
      visible={props.visible}
      onOk={props.onOk}
      onCancel={props.onCancel}
    >
      <Table dataSource={data} columns={columns} pagination={{ pageSize: 5 }} />
      <Button type="primary" htmlType="button" onClick={addItem}>
        Tambah Barang
      </Button>
    </Modal>
  );
};

export default ModalBarang;

prototype26
  • 121
  • 11
  • Maybe it has to do with you app structure. Have you checked for unwanted component renders?: useEffect(() => { console.log(data)}, [data]) – Pelayo Méndez May 05 '21 at 11:13
  • Hello i have added the link to codesandbox for easier navigation. When I check the data content inside useeffect its showing the correct newrst content. Its just the data state inside the removeItem component thats behaving weirdly. – prototype26 May 05 '21 at 11:32

4 Answers4

2

Let's try something like this instead:

const removeItem = (key) => {
  setData(prevData => prevData.filter(item => item.key !== key));
};
Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
  • See the note in [functional updates](https://reactjs.org/docs/hooks-reference.html#functional-updates) and [What is the use of functional syntax of setState in react functional components?](https://stackoverflow.com/q/65277471/15497888). Related: [What is the difference between passing an object or a function in setState?](https://reactjs.org/docs/faq-state.html#what-is-the-difference-between-passing-an-object-or-a-function-in-setstate) – Henry Ecker May 05 '21 at 13:23
1

You can use the ES6 spread operator to clone the old array resulting in a new array like so setData([...newItems])

Eli Himself
  • 834
  • 3
  • 8
  • 20
0

when you change object react dont understand the changes you should do it like this:

setData([...newItems]);
Ali Najafi
  • 124
  • 5
  • Like I said, the data is able to get updated to the newest one including the added items and it is working fine except when I try to see the data content inside the removeItem component. Outside of that one particular component, the data has the correct newest version (works fine inside the addItem or useEffect). – prototype26 May 05 '21 at 11:52
0

The difference between the two methods is the scope from where they are being called. As you are using a complex tablet component maybe you should refer to your library documentation, cause it seems the components inside the table are cached somehow. Without knowing how that component works you can change your button to:

<Button
 type="default"
 danger="true"
 onClick={() => setItemToRemove(record.key) }
>
Hapus Barang
</Button>

An then you can do something like this in your parent component:

const [itemToRemove, setItemToRemove] = useState();
      
useEffect(() => { 
   console.log(data)
   console.log(itemToRemove)}
   // ...
, [itemToRemove]) 
Pelayo Méndez
  • 389
  • 4
  • 10