Home > database >  Unexpected useState behaviour in ant design table
Unexpected useState behaviour in ant design table

Time:12-22

I have ant design form and table side by side,When I fill the form data and click on add entity button the data should be displayed in the table. Now the data does get rendered when I click on add entity but again when I fill the form and click on the add entity button the previous data gets disappeared, Now I know that I need to copy the previous data and I did that too but its not working.

My Problem:- The previous form state value which is rendered in the table gets disappeared when new form data is added

My query:- How and Where should I copy the previous object with the spread operator so that it does not get reset.

The UI

My code is

import { Card, Table } from "antd";
import { Form, Input, Button, Select, Space, AutoComplete } from "antd";
import { DeleteOutlined, PlusOutlined, SendOutlined } from "@ant-design/icons";
import { useState } from "react";


const ExampleComponent = (props) => {
  // Destructuring props
  const { intent_data, entity_data } = props;
  
  const [dataSource, setDataSource] = useState([{}]);
  // To handle the disable state of Select Entity Select DropDown
  const [addentity,setAddEntity] = useState(false)
  // Handler function passed to YES/NO Select Option
  const addEntityHandler = (addEntity) => {
    if(addEntity === 'no'){
      setAddEntity(true)
    }else{
      setAddEntity(false)
    }
  }
  
  const [form] = Form.useForm();
  const onFinish = (values) => {
    console.log(values);
    form.resetFields();
    const dataArr = [];
    // Push values to array since dataSource takes array not an object
    dataArr.push(values);
    setDataSource(dataArr);
  };
  const columns = [
    {
      title: "Entity",
      dataIndex: "entity_name",
      key: "entity_name",
    },
    {
      title: "Entity Value",
      dataIndex: "entity_value",
      key: "entity_value",
    },
    {
      title: "Operation",
      key: "operation",
      render: (record: any) => (
        <DeleteOutlined
          style={{ color: "red" }}
          onClick={() => console.log(record)}
        />
      ),
    },
  ];
  return (
    <Card className="csi-project-card-0934">
      <div className="example-layout">
        <div style={{ flexBasis: "100%" }}>
          <Form
            form={form}
            labelCol={{ span: 7 }}
            wrapperCol={{ span: 10 }}
            layout="horizontal"
            colon={true}
            onFinish={onFinish}
            size="large"
          >
            {/* <h4>Create Example</h4> */}
            <Form.Item
              label="Select Intent"
              name="intent_name"
              className="csi-ant-form-item"
              rules={[{ required: true, message: "Intent Cannot be Empty!" }]}
            >
              <Select>
                {/* {intent_data?.map?.((value) => (
                  <Select.Option
                    key={value.intent_ID}
                    value={value.intent_name}
                  >
                    {value.intent_name}
                  </Select.Option>
                ))} */}
                <Select.Option value="intent demo">Intent Demo</Select.Option>
                <Select.Option value="intent test">Intent Test</Select.Option>
              </Select>
            </Form.Item>
            <Form.Item
              label="Enter Example"
              name="example_name"
              className="csi-ant-form-item"
              hasFeedback
              rules={[
                { required: true, message: "This Field Cannot be Empty!" },
                ({ getFieldValue }) => ({
                  validator(_, value) {
                    if (value.length < 4) {
                      return Promise.reject("Length too short");
                    }
                    return Promise.resolve();
                  },
                }),
              ]}
            >
              <AutoComplete>
                <Input allowClear/>
              </AutoComplete>
            </Form.Item>
            <Form.Item
              label="Do you want to add Entity"
              name="add_entity"
              className="csi-ant-form-item"
              rules={[{ required: true, message: "This Cannot be Empty!" }]}
            >
              <Select placeholder="SELECT" onSelect={(addEntity) => addEntityHandler(addEntity)}>
                <Select.Option value="yes">YES</Select.Option>
                <Select.Option value="no">NO</Select.Option>
              </Select>
            </Form.Item>

            <Form.Item
              label="Select Entity"
              name="entity_name"
              className="csi-ant-form-item"
            >
              <Select disabled = {addentity}>
                <Select.Option value="entity demo">Entity Demo</Select.Option>
                <Select.Option value="entity test">Entity Test</Select.Option>
              </Select>
            </Form.Item>
            <Form.Item
              label="Select Value"
              name="entity_value"
              className="csi-ant-form-item"
              hasFeedback
              rules={[
                { required: true, message: "This Field Cannot be Empty!" },
              ]}
            >
              <AutoComplete>
                <Input placeholder="Select Value from Example" />
              </AutoComplete>
            </Form.Item>

            <Form.Item className="csi-ant-form-item">
              <Button
                key="submit"
                type="primary"
                htmlType="submit"
                shape="round"
              >
                Add Entity <PlusOutlined />
              </Button>
            </Form.Item>
          </Form>
        </div>
        <div
          style={{
            flexBasis: "100%",
            display: "flex",
            flexDirection: "column",
            alignItems: "center",
          }}
        >
          <Table
            bordered
            className="ib-table"
            dataSource={dataSource}
            columns={columns}
            pagination={{ pageSize: 6 }}
            rowKey={Math.random().toString()}
          />
          <Button key="submit" type="primary" htmlType="submit" shape="round">
            Submit <SendOutlined />
          </Button>
        </div>
      </div>
    </Card>
  );
};
export default ExampleComponent;

The form data is stored in values object and the structure of values is

{
add_entity: "yes"
entity_name: "entity demo"
entity_value: "Test"
example_name: "Test"
intent_name: "intent demo"
}

One thing to note here is that dataSource state variable is array of objects, like

[{
add_entity: "yes"
entity_name: "entity demo"
entity_value: "Test"
example_name: "Test"
intent_name: "intent demo"
}]

My Expected Output is Below

Entity Entity Value Operation
entity demo test delete icon
intent demo test delete icon

CodePudding user response:

What if you try with

setDataSource(prevDataSource => [...prevDataSource, values]);

?

In the same way, to delete an item:

{
      title: "Operation",
      key: "operation",
      render: (record) => (
        <DeleteOutlined
          style={{ color: "red" }}
          onClick={() => {
            setDataSource(prevDataSource => prevDataSource.filter(item => item.entity_name !== record.entity_name //entity_name or whatever id the item has ))
          }}
        />
      ),
    },

By the way, try to avoid using any whenever possible if you're using typescript. Here is how to:

import { Table } from 'antd';
import { ColumnsType } from 'antd/es/table';

interface User {
  key: number;
  name: string;
}

const columns: ColumnsType<User> = [
  {
    key: 'name',
    title: 'Name',
    dataIndex: 'name',
  },
];

const data: User[] = [
  {
    key: 0,
    name: 'Jack',
  },
];

export default () => (
  <>
    <Table<User> columns={columns} dataSource={data} />
    /* JSX style usage */
    <Table<User> dataSource={data}>
      <Table.Column<User> key="name" title="Name" dataIndex="name" />
    </Table>
  </>
);
  • Related