reactjs - Πώς μπορώ να σταματήσω την επανασχεδίαση του TanStack React Table μέχρι να ολοκληρωθεί η εισαγωγή στο πεδίο εισόδου;


Δημιουργώ έναν πίνακα στον οποίο μπορεί να εισαχθεί η τιμή μονάδας σε μια στήλη και μια άλλη στήλη υπολογίζει την συνολική τιμή βάσει της εισαγόμενης τιμής και της τιμής από μια άλλη στήλη «Ποσότητα» (συνολική τιμή=ποσότητα * τιμή μονάδας). Αυτό το υλοποίησα σε κανονικό πίνακα στο React χωρίς καμία βιβλιοθήκη, αλλά ήθελα να υλοποιήσω φιλτράρισμα και ταξινόμηση, οπότε αποφάσισα να το μεταφέρω στον TanStack Table.

Το πρόβλημα είναι ότι το στοιχείο εισαγωγής αποεπιλέγεται αμέσως μόλις εισάγω ακόμη και ένα μόνο χαρακτήρα στην εισαγωγή. Βρήκα ότι η αιτία μπορεί να είναι ότι ο πίνακας ξανασχεδιάζεται μόλις εισάγω ακόμη και ένα μόνο χαρακτήρα, οπότε δεν μπορώ να εισάγω ολόκληρη την είσοδο. Πώς να διορθώσω αυτό το πρόβλημα;

const defaultColumns = [

    // Accessor Column
    columnHelper.accessor("totalQty", {
      cell: (info) => info.getValue(),
      footer: (props) => props.column.id,
      header: () => <span>Quantity</span>,
    }),
    // ...other columns
    // Accessor Column
    columnHelper.accessor("unitPrice", {
      header: "Unit Price",
      footer: (props) => props.column.id,
      cell: (props) => (
        <input
          type="number"
          className="number-input"
          value={props.row.original.unitPrice}
          onChange={(e) => {
            handleUnitPriceChange(props.row.index, Number(e.target.value));
          }}
        />
      ),
    }),
    // Accessor Column
    columnHelper.accessor(
      (row) => {
        return row.totalQty ? row.totalQty * row.unitPrice : null;
      },
      {
        header: "Total Price",
        footer: (props) => props.column.id,
        cell: (props) => (
          <span>
            {props.row.original.totalQty
              ? props.row.original.totalQty * props.row.original.unitPrice
              : null}
          </span>
        ),
      }
    ),
  ];
  const table = useReactTable({
    data,
    columns: defaultColumns,
    getCoreRowModel: getCoreRowModel(),
  });

Αυτή είναι η συνάρτηση που ενημερώνει την τιμή μονάδας στη λίστα αντικειμένων:

function handleUnitPriceChange(index: number, up: number | null) {
    const updatedPurchaseReq = { ...purchaseReq };
    if (up !== null) {
      updatedPurchaseReq.itemList[index].unitPrice = up;
      updatedPurchaseReq.itemList[index].totalCost =
        up * updatedPurchaseReq.itemList[index].totalQty;
    } else {
      updatedPurchaseReq.itemList[index].unitPrice = 0;
      updatedPurchaseReq.itemList[index].totalCost = 0;
    }
    setPurchaseReq(updatedPurchaseReq);
  }

Πώς να διορθώσετε το πρόβλημα που το πεδίο εισαγωγής αποεπιλέγεται μετά από κάθε χαρακτήρα που εισάγεται;

Έχω προσπαθήσει να διορθώσω την επαναφόρτωση χρησιμοποιώντας το useMemo αλλά δεν λειτούργησε. Ο πίνακας επαναφορτώνεται μόλις εισαχθεί ένας χαρακτήρας.

Απάντηση #1

Μετά την ανάγκη να βρω μια απάντηση γι' αυτό ο ίδιος, τελικά έριξα μια ματιά στο σχόλιο του Iorweth333 για το Material React Table για να δω πώς το έκανε.

Αποδεικνύεται ότι σχεδόν όλα όσα κάνουν βασίζονται σε onBlur και όχι σε onChange, οπότε κατάφερα να βρω αυτή τη λύση χρησιμοποιώντας React Hook Form και Shadcn στην περίπτωσή μου:

Στη δική σου περίπτωση, πιθανότατα θα έκανα αυτές τις αλλαγές και θα έβλεπα αν δουλεύει (αν και αυτή η ανάρτηση έγινε πριν δύο μήνες τώρα):

columnHelper.accessor("unitPrice", {
  header: "Unit Price",
  footer: (props) => props.column.id,
  cell: (props) => (
    <input
      type="number"
      className="number-input"
      defaultValue={props.row.original.unitPrice}
      onBlur={(e) => {
        handleUnitPriceChange(props.row.index, Number(e.target.value));
      }}
    />
  ),
}),

Σε περίπτωση που κάποιος άλλος έχει το ιδιαίτερο πρόβλημά μου, ιδού τι έκανα:

{
  accessorKey: 'amount',
  header: 'Amount',
  cell: ({ row }) => {
    const index = row.index
    return (
      <FormField
        control={form.control}
        name={`invoiceGlCodes.${index}.amount`}
        render={({ field: { onChange, onBlur, value, ...fieldProps } }) => (
          <FormItem>
            <FormControl>
              <Input
                type="text"
                defaultValue={value}
                onBlur={(event) => {
                  onChange(event)
                  onBlur()
                }}
                {...fieldProps}
              />
            </FormControl>
            <FormMessage />
          </FormItem>
        )}
      />
    )
  },
},

Παρατηρήστε επίσης ότι χρησιμοποιώ defaultValue αντί για value, γιατί θα σας επιτρέψει να ενημερώσετε την είσοδο πριν την αποθηκεύσετε στην κατάσταση.