You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用ReactJS向react-select下拉组件动态新增选项

问题描述

我有一个基于react-select依赖提供的Select组件实现的下拉组件,在下拉选项列表中添加了一个按钮,需求为点击该按钮后可输入文本,按下回车键时将输入的文本添加到下拉选项列表中。曾尝试将初始选项列表存储在state变量中后执行更新操作,但未达到预期效果,组件实现代码如下:

import React from "react";
import PropTypes from "prop-types";
import Select from "react-select";
import { get } from "../../helpers";
const ReactSelect = props => {

    const { state, component, onChange, disabled = false } = props;
    let showError = false;
    const {
        name,
        placeholder,
        optionConfig = false,
        optionList = [],
        className,
        maxItems = null
        
    } = component;
    
    const newOptionList=[
        ...optionList,
        {label: (
            <>
                <hr />
                <button
                    className="btn btn-icon" >
                    <cds-icon shape="plus"></cds-icon>ADD TYPE
                </button>
            </>
        ),
        value: "Add Type"}
    ];
    const options = !!optionConfig ? get(state, `${optionConfig}`, []) : newOptionList;
    
    const getSelectValue = () => {
        const selectedList = get(state, `${name}`, []);
        const selectedSet = new Set(selectedList);
        return options.filter(item => selectedSet.has(item.value));
    };

    const handleOnChange = selectedOption => {
        console.log(selectedOption);
        if(selectedOption.value !== "Add Type"){
            console.log(selectedOption);
            onChange({ value: selectedOption, component });
        } else {
            console.log("button selected");
            onChange({ value: selectedOption, component });
        }
    };

    const defaultSelectProps = {
        value: getSelectValue(),
        name: "category",
        options,
        menuPosition: "absolute",
        isDisabled: disabled,
        placeholder
    };

    return (
        <div  key={name}>
           
            <div className={`react-select-box ${className}`}>
                <Select
                    {...defaultSelectProps}
                   
                />
                {
                    showError &&
                    <span className="clr-subtext multiselect-error">
                        You can select upto {maxItems} items only.
                    </span>
                }
            </div>

        </div>

    );
};

ReactSelect.propTypes = {
    selectWithoutBox: PropTypes.bool
};

ReactSelect.defaultProps = {
    selectWithoutBox: false
};
export default ReactSelect;

上述代码中,getSelectValue函数负责返回用户选中的选项并完成展示,引入的get工具方法实现如下:

export function get(source, path, defaultValue) {
if (typeof path === "number") {
    path = String(path);
}

if (path && source) {
    let parts = path.split(".");
    let length = parts.length;
    let result = source;

    for (let i = 0; i < length; i++) {
        let item = result[parts[i]];

        if (item === null || item === undefined) {
            return item || defaultValue;
        }

        result = item;
    }

    return result;
}

return defaultValue;
}

需要修改代码实现向下拉组件选项列表中动态添加新增值的功能。

问题原因
  • 选项列表每次渲染都直接基于component.optionList临时拼接,没有独立状态存储动态新增的选项,新增值无法持久保留
  • 自定义的"ADD TYPE"按钮没有拦截默认选中事件,点击后会被当做普通选项提交,没有触发输入流程
  • 没有对接react-select的创建选项能力,回车输入的文本无法被识别为新选项加入列表
修改方案

直接使用react-select官方提供的CreatableSelect组件实现创建选项能力,搭配本地状态存储动态新增的选项,同时给自定义添加按钮绑定事件拦截默认行为、触发输入框聚焦,修改后的完整代码如下:

import React, { useState, useRef } from "react";
import PropTypes from "prop-types";
import CreatableSelect from "react-select/creatable";
import { get } from "../../helpers";

const ReactSelect = props => {
    const { state, component, onChange, disabled = false } = props;
    const selectRef = useRef(null);
    let showError = false;
    const {
        name,
        placeholder,
        optionConfig = false,
        optionList = [],
        className,
        maxItems = null
    } = component;

    // 本地存储动态新增的选项,初始值为传入的默认选项
    const [customOptions, setCustomOptions] = useState(optionList);

    // 拼接最终选项列表,尾部固定添加操作按钮,标记isDisabled防止被当成普通选项选中
    const finalOptions = [
        ...(!!optionConfig ? get(state, `${optionConfig}`, []) : customOptions),
        {
            label: (
                <>
                    <hr />
                    <button
                        className="btn btn-icon"
                        onClick={(e) => {
                            // 阻止事件冒泡,防止触发选项选中
                            e.stopPropagation();
                            e.preventDefault();
                            // 聚焦到select输入框,进入输入态
                            selectRef.current?.focus();
                        }}
                    >
                        <cds-icon shape="plus"></cds-icon>ADD TYPE
                    </button>
                </>
            ),
            value: "Add Type",
            isDisabled: true
        }
    ];
    
    const getSelectValue = () => {
        const selectedList = get(state, `${name}`, []);
        const selectedSet = new Set(selectedList);
        return finalOptions.filter(item => selectedSet.has(item.value));
    };

    // 处理回车创建新选项的逻辑
    const handleCreateOption = (inputValue) => {
        // 去重判断
        const isExist = finalOptions.some(opt => opt.value === inputValue);
        if (isExist) return;
        const newOption = {
            label: inputValue,
            value: inputValue
        };
        // 更新本地选项列表
        setCustomOptions(prev => [...prev, newOption]);
        // 自动选中新创建的选项
        const currentSelected = getSelectValue();
        onChange({ value: [...currentSelected, newOption], component });
    };

    const handleOnChange = selectedOption => {
        onChange({ value: selectedOption, component });
    };

    const defaultSelectProps = {
        ref: selectRef,
        value: getSelectValue(),
        name: "category",
        options: finalOptions,
        menuPosition: "absolute",
        isDisabled: disabled,
        placeholder,
        onCreateOption: handleCreateOption,
        isMulti: true // 单选场景可删除该配置
    };

    return (
        <div key={name}>
            <div className={`react-select-box ${className}`}>
                <CreatableSelect
                    {...defaultSelectProps}
                />
                {
                    showError &&
                    <span className="clr-subtext multiselect-error">
                        You can select upto {maxItems} items only.
                    </span>
                }
            </div>
        </div>
    );
};

ReactSelect.propTypes = {
    selectWithoutBox: PropTypes.bool
};

ReactSelect.defaultProps = {
    selectWithoutBox: false
};
export default ReactSelect;

关键修改点说明

  • 引入CreatableSelect替换原生Select,自带输入创建选项的能力,不需要额外实现输入框
  • 新增customOptions本地状态,存储动态新增的选项,解决之前选项每次渲染重置的问题
  • 给尾部的"ADD TYPE"选项加isDisabled: true标记,防止被当做普通选项选中,同时给按钮绑定点击事件,拦截默认行为后触发输入框聚焦
  • 实现onCreateOption回调,处理回车创建新选项的逻辑,做去重校验后更新选项列表,自动选中新添加的选项

内容的提问来源于stack exchange,提问作者Rimmi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 23:51:15