javascriptreactjsantd

Unable to bind an object as a value for Select component (Ant Design) in react js


I have an issue while selecting the object as value for Select component (Ant Design).

This is what I'm trying to do

import React, { useEffect, useState } from "react";
//Other imports

export const NewInvoice = () => {
    const [selectedCustomer, setSelectedCustomer] = useState(null);
    const [customers, setCustomers] = useState([]);
    
    // other fields


    useEffect(() => {
        if (checkAuthentication(getToken())) {
            fetchCustomers().then((data) => {
                setCustomers(data);
            });
        }
        //eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

    const customerNameHelper = (customer) => {
        return `${customer?.customerNumber ?? ""} - ${customer?.name ?? "Unkown"}, ${customer?.addressDto?.city ?? "Unknown"}`;
    };

    const getCustomerAsOptions = (customers) => {
        return customers.map((item) => ({
            label: customerNameHelper(item),
            value: item, // item = {id, name, customerNumber, ...}
        }));
    };
    
    return (
        // other components
        {customers.length > 0 && (
            <Select
                style={{
                    width: 380,
                }}
                className="customerSelectionDropdown"
                value={customerNameHelper(selectedCustomer)}
                onChange={(value) => {
                    setSelectedCustomer(value);
                }}
                placeholder="Select Customer"
                options={getCustomerAsOptions(customers)}
                dropdownStyle={dropDownStyles}
                showSearch
                allowClear
            />
        )}
    );
};

Whenever I try to select the option it is saying Objects are not valid as a React child (found: object with keys {id, name, customerNumber, email, phone, pendingAmount, createdDate, addressDto, totalPurchaseAmount}). If you meant to render a collection of children, use an array instead.

Is there any solution to address this issue? Thank you in advance for your assistance.


Solution

  • You are sending an object to property value in getCustomerAsOptions

    CODESANDBOX

      const getCustomerAsOptions = (customers) => {
        return customers.map((item) => ({
          label: customerNameHelper(item),
    
          // CHANGE
          value: item.customerNumber, // item = {id, name, customerNumber, ...}
        }));
      };
    

    Type of the Option in antd is string | number | null:

        label: React.ReactNode;
        value?: string | number | null;
    

    You have to pass only string | number | null and you are passing an object which throws error.

    IMO: You should pass unique identifier so that on selecting a value from dropdown you can identify which element has been clicked. On click of an option it will return same value to you in onChange callback

      onChange={(value) => {
        setSelectedCustomer(value);
      }}
    

    MODIFICATION: If you want to tract the object then you can create state and set it in onChange callback as:

    onChange={(value) => {
      const selectedCust = customers.find(
        (o) => o.customerNumber === value,
      );
      if (selectedCust) setSelectedCustomer(selectedCust);
    }}
    

    MODIDFICATION 2: If you want to set the selected object then you can use second args to onChange as:

    onChange={(value, selectedCust) => {
      setSelectedCustomer(selectedCust);
    }}