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

Ant Design可编辑标签组类组件转React函数组件报错问题求助

问题修复方案

错误原因

  • 状态丢失问题:函数组件的useState返回的更新函数不会自动合并剩余状态,你每次仅传入部分状态字段时,其余字段会被直接覆盖丢失,导致state.tags变为undefined,调用map方法时报错。
  • setState回调不支持问题:函数组件的状态更新函数不支持类组件setState的第二个回调参数,你需要通过useEffect监听对应状态变化,来执行状态更新后的后续操作(比如输入框自动聚焦)。
  • ref调用错误:通过useRef创建的引用需要访问.current属性才能拿到对应的DOM实例,原代码中直接调用input.focus()、editInput.focus()会报错。
  • 组件导入缺失:原改写代码未导入用到的Tag、Input、Tooltip组件。

修正后完整代码

import { PlusOutlined } from '@ant-design/icons';
import { useRef, useState, useEffect } from 'react';
import { Tag, Input, Tooltip } from 'antd';

const Tags = () => {
  const [state, setState] = useState({
    tags: ['Unremovable', 'Tag1', 'Tag2', 'Tag3'],
    inputVisible: false,
    inputValue: '',
    editInputIndex: -1,
    editInputValue: '',
  });
  const inputRef = useRef(null);
  const editInputRef = useRef(null);

  // 监听新增标签输入框显示状态,自动聚焦
  useEffect(() => {
    if (state.inputVisible) {
      inputRef.current?.focus();
    }
  }, [state.inputVisible]);

  // 监听编辑状态,自动聚焦编辑输入框
  useEffect(() => {
    if (state.editInputIndex !== -1) {
      editInputRef.current?.focus();
    }
  }, [state.editInputIndex]);

  const handleClose = removedTag => {
    const tags = state.tags.filter(tag => tag !== removedTag);
    setState(prev => ({...prev, tags }));
  };

  const showInput = () => {
    setState(prev => ({...prev, inputVisible: true }));
  };

  const handleInputChange = e => {
    setState(prev => ({...prev, inputValue: e.target.value }));
  };

  const handleInputConfirm = () => {
    const { inputValue, tags } = state;
    let newTags = [...tags];
    if (inputValue && tags.indexOf(inputValue) === -1) {
      newTags = [...tags, inputValue];
    }
    setState(prev => ({
      ...prev,
      tags: newTags,
      inputVisible: false,
      inputValue: '',
    }));
  };

  const handleEditInputChange = e => {
    setState(prev => ({...prev, editInputValue: e.target.value }));
  };

  const handleEditInputConfirm = () => {
    setState(prev => {
      const newTags = [...prev.tags];
      newTags[prev.editInputIndex] = prev.editInputValue;
      return {
        ...prev,
        tags: newTags,
        editInputIndex: -1,
        editInputValue: '',
      };
    });
  };

  const { tags, inputVisible, inputValue, editInputIndex, editInputValue } = state;

  return (
    <>
      {tags.map((tag, index) => {
        if (editInputIndex === index) {
          return (
            <Input
              ref={editInputRef}
              key={tag}
              size="small"
              className="tag-input"
              value={editInputValue}
              onChange={handleEditInputChange}
              onBlur={handleEditInputConfirm}
              onPressEnter={handleEditInputConfirm}
            />
          );
        }

        const isLongTag = tag.length > 20;

        const tagElem = (
          <Tag
            className="edit-tag"
            key={tag}
            closable={index !== 0}
            onClose={() => handleClose(tag)}
          >
            <span
              onDoubleClick={e => {
                if (index !== 0) {
                  setState(prev => ({
                    ...prev,
                    editInputIndex: index,
                    editInputValue: tag
                  }));
                  e.preventDefault();
                }
              }}
            >
              {isLongTag ? `${tag.slice(0, 20)}...` : tag}
            </span>
          </Tag>
        );
        return isLongTag ? (
          <Tooltip title={tag} key={tag}>
            {tagElem}
          </Tooltip>
        ) : (
          tagElem
        );
      })}
      {inputVisible && (
        <Input
          ref={inputRef}
          type="text"
          size="small"
          className="tag-input"
          value={inputValue}
          onChange={handleInputChange}
          onBlur={handleInputConfirm}
          onPressEnter={handleInputConfirm}
        />
      )}
      {!inputVisible && (
        <Tag className="site-tag-plus" onClick={showInput}>
          <PlusOutlined /> 新增标签
        </Tag>
      )}
    </>
  )
};

export default Tags;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 13:48:04