admin管理员组

文章数量:1413471

I am using react-select to display a CreatableSelect dropdown. This drop down is controlled using react-hook-form. I have implemented the onCreateOption handler on the CreatableSelect. My handler then shows a Modal (React Bootstrap) which allows the user to fill in all details and then save the item. This modal component then calls a function as supplied to it, allowing the select component to listen for changes. Basically, the item to be added is saved successfully and the ID for this item is returned (which can be optimized, but that is beside the point for now).

This is my onCreateItem function;

    const onCreateItem = (itemID: string) => {
    setCreatingItem(false); // hide the modal

    fetchReference(field.referencedModuleIdx, itemID).
        then((reference) => {
            let option: IconSelectOption = {
                value: reference.id, id: reference.id, label: reference.name, iconUrl: reference.iconUrl
            }

            setOptions((options) => [...options, option]);
            setSelectedValue(option); //no ?
            setValue("inputfield-" + field.index, option); //no ?
         }
    );
}  

The component in question looks as follows:

return (
    <>
        {creatingItem === true && <ItemCreateModal show={creatingItem} moduleIdx={field.referencedModuleIdx} onCreateItem={onCreateItem} value={input} />}

        <Controller
            name={"inputfield-" + field.index}
            key={"inputfield-" + field.index}
            defaultValue={selectedValue}
            rules={{ required: field.required }}
            render={renderProps => {
                return (
                    <CreatableSelect
                        className="react-select-container"
                        classNamePrefix="react-select"
                        options={options}
                        isClearable
                        isSearchable
                        placeholder="..."
                        isDisabled={field.readOnly}
                        components={{ Option: IconOption, Control }}
                        {...register("inputfield-" + field.index)}
                        {...renderProps.field}
                        onCreateOption={(value) => handleCreateOption(value)}
                        onChange={e => {
                            setSelectedValue(e as IconSelectOption);
                            renderProps.field.onChange(e);
                        }}
                    />
                );
            }}
       />
    </>
)

and has the following defined:

const [creatingItem,  setCreatingItem] = useState(false);
const [options, setOptions] = useState<IconSelectOption[]>(getOptions());
const [selectedValue, setSelectedValue] = useState<IconSelectOption>(getCurrentValue());
const [input, setInput] = useState("");
const { setValue } = useForm();
const { register } = useFormContext();

And that is where I get stuck;

  • I do get the item added to the list of options; its actively showing and I can select it.
  • But, I cannot make it the selected value.

I am still pretty new to React. I thought that I could get the select to be refreshed/updated either via the state controlled value selectedValue or either via setValue from the react-hook-form. But whatever I do, the old selected value remains selected and the new value is sitting in the list but remains unselected.

Can anyone point me in the right direction?

For references, the whole piece of code:

    import { components, type ControlProps, type GroupBase, type OptionProps } from 'react-select'
import CreatableSelect from 'react-select/creatable';
import type { JSX } from 'react/jsx-runtime';
import { useState } from 'react';
import type { InputFieldComponentProps } from './dc_input_field';
import { useFormContext, Controller, useForm } from 'react-hook-form';
import { ItemCreateModal } from '../../pages/item/item_create_modal';
import { fetchReference, type Reference } from '../../services/datacrow_api';

export interface IconSelectOption {
    value: string;
    label: string;
    iconUrl: string;
    id: string;
}

const { Option } = components;

const IconOption = (props: JSX.IntrinsicAttributes & OptionProps<IconSelectOption, boolean, GroupBase<IconSelectOption>>) => (
    <Option {...props}>
    
        {props.data.iconUrl && (
            <img
                src={props.data.iconUrl}
                key={props.data.iconUrl}
                style={{ width: "24px", paddingRight: "8px" }}
            />
        )}

        {props.data.label}
    </Option>
);

export default function DcReferenceField({
    field,
    value,
    references
}: InputFieldComponentProps) {

    const [creatingItem,  setCreatingItem] = useState(false);
    const [options, setOptions] = useState<IconSelectOption[]>(getOptions());
    const [selectedValue, setSelectedValue] = useState<IconSelectOption>(getCurrentValue());
    const [input, setInput] = useState("");
    const { setValue } = useForm();
    const { register } = useFormContext();
    
    function getCurrentValue() {
        let idx = 0;
        let selectedIdx = -1;

        options.forEach((option) => {
            if (option.value === (value as Reference).id)
                selectedIdx = idx;
                
            idx++;
        });
    
        return options[selectedIdx];
    }

    const handleCreateOption = (value: string) => {
        setInput(value);
        setCreatingItem(true);
    }
    
    const onCreateItem = (itemID: string) => {
        setCreatingItem(false); // hide the modal

        fetchReference(field.referencedModuleIdx, itemID).
            then((reference) => {
                let option: IconSelectOption = {
                    value: reference.id, id: reference.id, label: reference.name, iconUrl: reference.iconUrl
                }

                setOptions((options) => [...options, option]);
                setSelectedValue(option); //no ?
                setValue("inputfield-" + field.index, option); //no ?
             }
        );
    }  
    
    function getOptions() {

        let options: IconSelectOption[] = [];

        if (references && references.items) {
            references.items.map(reference =>
                options.push({ id: reference.id, value: reference.id, label: reference.name, iconUrl: reference.iconUrl }),
            );
        }

        return options;
    }

    const Control = ({ children, ...props }: ControlProps<IconSelectOption, boolean, GroupBase<IconSelectOption>>) => (
        <components.Control {...props}>
            {(  (selectedValue && selectedValue.iconUrl)) && (
                <img
                    src={selectedValue?.iconUrl}
                    style={{ width: "24px", paddingLeft: "8px" }} />
            )}
            {children}
        </components.Control>
    );

    return (
        <>
            {creatingItem === true && <ItemCreateModal show={creatingItem} moduleIdx={field.referencedModuleIdx} onCreateItem={onCreateItem} value={input} />}

            <Controller
                name={"inputfield-" + field.index}
                key={"inputfield-" + field.index}
                defaultValue={selectedValue}
                rules={{ required: field.required }}
                render={renderProps => {
                    return (
                        <CreatableSelect
                            className="react-select-container"
                            classNamePrefix="react-select"
                            options={options}
                            isClearable
                            isSearchable
                            placeholder="..."
                            isDisabled={field.readOnly}
                            components={{ Option: IconOption, Control }}
                            {...register("inputfield-" + field.index)}
                            {...renderProps.field}
                            onCreateOption={(value) => handleCreateOption(value)}
                            onChange={e => {
                                setSelectedValue(e as IconSelectOption);
                                renderProps.field.onChange(e);
                            }}
                        />
                    );
                }}
           />
        </>
    )
}

本文标签: javascriptCreateable Select trying to add and item and make it selectedStack Overflow