update the form in react

32 Views Asked by At

I have a code in react using devextreme code blocks which contains several fields along with it. two buttons which one add newrow and one deletes it's corresponding row. Since my component is sending the data everytime when it changes with out any button I had used onBlur to change the state with a cost of double click. But my user want them to be update in one click. So is there any way to do this particular action. my code

import React, { useState, useEffect } from "react";
import apis from "../api-constants";
import './temporarystack.scss';
import DataGrid, { Column } from "devextreme-react/data-grid";
import useGetAPI from "../getAPIS";
import { Button, SelectBox } from "devextreme-react";
import { formatMessage } from "devextreme/localization";

function TemporaryStack({ tokenDetails, operation, isTempUsed, temporaryStacksJSON }) {

  const [showTable, setShowTable] = useState(false);
  const [listData, setListData] = useState([{
    shed: '',
    storageType: '',
    assignedBags: '',
    fcapacity: '',
    maxBags: '',
    lead: '',
    bagsPerLayer: '',
    location: '',
    comment: '',
  }]);
  const [shedOptions, setShedOptions] = useState(null);
  const [threshold, setThreshold] = useState({})
  const storageTypeOptions = [
    { id: 1, name: 'Gangway' },
    { id: 2, name: 'Alleyway' },
    { id: 3, name: 'Road Side' },
    { id: 4, name: 'Plinth' },
    { id: 5, name: 'Other' }
  ]


  useEffect(() => {

    async function Dataapi() {
      const responceforshed = await useGetAPI(apis.GET_GODOWN_UNITS(operation))
    const responceforthreshold = await useGetAPI(apis.GET_BAGWEIGHT_THRESHOLD_MAXIMUXBAGCAPACITY)
      setShedOptions(responceforshed.data)
    setThreshold(responceforthreshold.data)
    }

    if (showTable === true) {
      Dataapi()
    }

  }, [operation, tokenDetails, showTable])
  useEffect(() => {
    temporaryStacksJSON(listData.map(obj=>{
    const {fcapacity,storageType,location,comment,bagsPerLayer,assignedBags,lead,maxBags,shed}=obj
      return {
        fcapacity:fcapacity,
        storageType:storageType,
        location:location,
        comment:comment,
        bagsPerLayer:bagsPerLayer,
        assignedBags:assignedBags,
        flagRecordExists:true,
        isTemporaryStackUsed:true,
        lead:lead,
        maxBags:maxBags,
        mappedGenericId:tokenDetails.genericid,
        mappedGodownUnitId:shed
      }
    }))
  }, [listData])


  // removing data when Temporary stack is unchecked and initialization state
  const handleCheckboxChange = (e) => {
    const isChecked = e.target.checked;
    setShowTable(isChecked);
    isTempUsed(isChecked)
    if (!isChecked) {
      setListData([])
    }
  };

  // adding new row to the temporary stack
  const addRow = () => {
    const newItem = {
      shed: shedOptions && shedOptions.length > 0 ? shedOptions[0]?.value : '',
      storageType: storageTypeOptions.length > 0 ? storageTypeOptions[0].name : '',
      assignedBags: '',
      fcapacity: '',
      maxBags: '',
      lead: '',
      bagsPerLayer: '',
      location: '',
      comment: '',
    };
    setListData((prevList) => [...prevList, newItem]);

  };

  // to delete a temporary stack
  const deleteRow = (index) => {
    const updatedList = [...listData];
    updatedList.splice(index, 1);
    setListData(updatedList);
  };

  const DataRow = (rowInfo) => (
    <>
      <tr className="main-row">
        <td>
          {rowInfo.rowIndex + 1}
        </td>
        <td >
          <SelectBox
            dataSource={shedOptions}
            displayExpr={'value'}
            valueExpr={'id'}
            onValueChange={e => {
              const updatedList = [...listData];
              updatedList[rowInfo.rowIndex].shed = e;
              setListData(updatedList);
            }}
            value={rowInfo.data.shed}
            defaultValue={rowInfo.data.shed}
          />
        </td>
        <td>
          <SelectBox
            dataSource={storageTypeOptions}
            displayExpr="name"
            valueExpr="name"
            onValueChanged={e => {
              const updatedList = [...listData];
              updatedList[rowInfo.rowIndex].storageType = e.value;
              setListData(updatedList);
            }}
            value={rowInfo.data.storageType}
            defaultValue={rowInfo.data.storageType}
          />
        </td>
        <td>
          <input
            type="number"
            defaultValue={rowInfo.data.assignedBags}
            onBlur={(e) => {
              const updatedList = [...listData];
              updatedList[rowInfo.rowIndex].assignedBags = parseInt(e.target.value)
              setListData(updatedList);
            }}
            onKeyDown={(e) => {
              if (e.key === 'Enter') {
                e.preventDefault();
              }
            }}
          />
        </td>
        <td>
        <input
            type="number"
            defaultValue={rowInfo.data.fcapacity}
            onBlur={(e) => {
              const updatedList = [...listData];
              updatedList[rowInfo.rowIndex].fcapacity = parseInt(e.target.value)
              setListData(updatedList);
            }}
            onKeyDown={(e) => {
              if (e.key === 'Enter') {
                e.preventDefault();
              }
            }}
          />
        </td>
        <td>
          <input
            type="number"
            defaultValue={rowInfo.data.maxBags}
            onBlur={(e) => {
              const updatedList = [...listData];
              updatedList[rowInfo.rowIndex].maxBags = parseInt(e.target.value)
              setListData(updatedList);
            }}
            onKeyDown={(e) => {
              if (e.key === 'Enter') {
                e.preventDefault();
              }
            }}
          />
        </td>
        <td>
          <input

            type="number"
            defaultValue={rowInfo.data.lead}
            onBlur={(e) => {
              const updatedList = [...listData];
              updatedList[rowInfo.rowIndex].lead = parseInt(e.target.value)
              setListData(updatedList);
            }}
            onKeyDown={(e) => {
              if (e.key === 'Enter') {
                e.preventDefault();
              }
            }}
          />
        </td>
        <td>
          <input
            type="number"
            defaultValue={rowInfo.data.bagsPerLayer}
            onBlur={(e) => {
              const updatedList = [...listData];
              updatedList[rowInfo.rowIndex].bagsPerLayer = parseInt(e.target.value)
              setListData(updatedList);
            }}
            onKeyDown={(e) => {
              if (e.key === 'Enter') {
                e.preventDefault();
              }
            }}
          />
        </td>
        <td>
          <Button
            icon="close"
            onClick={() => deleteRow(rowInfo.rowIndex)}
            style={{
              borderRadius: '10%',
              padding: 0,
              width: '20px',
              height: '20px',
              minWidth: '20px',
              minHeight: '20px',
              lineHeight: '20px',
            }}
          />
        </td>


      </tr>
      <tr>
        <td></td>
        <td colSpan={2}>
          <div style={{ display: 'flex', alignItems: 'center' }}>
            <div>{formatMessage('LocationDescription')}</div>
            <textarea
              defaultValue={rowInfo.data.location}
              maxLength="25"
              onBlur={(e) => {
                const updatedList = [...listData];
                updatedList[rowInfo.rowIndex].location = (e.target.value)
                setListData(updatedList);
              }}
              onKeyDown={(e) => {
                if (e.key === 'Enter') {
                  e.preventDefault();
                }
              }}
            />
          </div>
        </td>
        <td colSpan={2}>
          <div style={{ display: 'flex', alignItems: 'center' }}>
            <div style={{ marginRight: '10px' }}>{formatMessage('Commentl')}</div>
            <textarea
              defaultValue={rowInfo.data.comment}
              maxLength="250"
              onBlur={(e) => {
                const updatedList = [...listData];
                updatedList[rowInfo.rowIndex].comment = (e.target.value)
                setListData(updatedList);
              }}
              onKeyDown={(e) => {
                if (e.key === 'Enter') {
                  e.preventDefault();
                }
              }}
            />
          </div>
        </td>
        <td></td>
        <td></td>
        <td></td>
        <td></td>



      </tr>
    </>
  );
  // rendering the table or state change for data
  const renderTable = () => {
    if (!showTable) return null;

    return (
      <>
        <DataGrid dataSource={listData} showBorders={true} dataRowRender={DataRow}>
          <Column width={25} />
          <Column caption={formatMessage("Shed")} />
          <Column caption={formatMessage('StorageType')} />
          <Column dataField="assignedBags" caption={formatMessage("AssignedBagInTemp")} />
          <Column dataField="fcapacity" caption={formatMessage('Capacity')} />
          <Column dataField="maxBags" caption={formatMessage('MaxBags')} />
          <Column dataField="lead" caption={formatMessage("Lead")} />
          <Column dataField="bagsPerLayer" caption={formatMessage('BagsPerLayer')} />
          <Column width={35} />

        </DataGrid>
        <Button
          onClick={addRow}
          icon="plus"
          className="small-button"
          style={{
            borderRadius: '10%',
            marginTop: '5px',
            padding: 0,
            width: '20px',
            height: '20px',
            minWidth: '20px',
            minHeight: '20px',
            lineHeight: '20px',
          }}
        />

      </>
    );
  };

  return (
    <>
      <label>
        <input type="checkbox" onChange={(e) => handleCheckboxChange(e)} />
        {formatMessage('TemporaryStack')}
      </label>
      {renderTable()}
    </>
  );
};

export default React.memo(TemporaryStack)

I had tried to use onChange but it was updating for every one character and the changeevent is nullified. One more thing this form is enclose with checkbox.

1

There are 1 best solutions below

0
Victoria Hill On

For achieving a one-click update in React with DevExtreme components, switch from using onBlur to onChange. This adjustment ensures your state updates immediately after a value changes, not just when the element loses focus. Remember to manage and debounce rapid state changes if your updates are resource-intensive, to maintain performance. This strategy provides a more responsive user experience by directly linking state changes to user actions without requiring an extra click.