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

React useState更新元素时重复生成同ID对象问题求助

React组件状态更新问题:对象ID重复导致无法正确存入数组

原本期望当对象ID唯一时将其存入useState管理的对象数组,但每次组件更新都会生成ID相同的新对象,existingObjectIndex始终返回-1,无法正确判断对象是否已存在。

控制台日志截图:
控制台日志截图

组件代码

function CreateQuestionSurvey({data, setData}) {
 const [questionType, setQuestionType] = useState("");
 const questionTypeString = useRef()
 const [question,setQuestion] = useState("")
 const [questionAnswers, setQuestionAnswers] = useState()

 const [object, setObject] = useState({
    'question': '', 
    'type':'',
    'possibleAnswers' : '',
    'id': crypto.randomUUID()
 })
console.log('setObject', object);
useEffect(() =>{
  const updatedObject = { ...object ,
        'question': question, 
        'type':questionTypeString.current?.value,
        'possibleAnswers' : questionAnswers,
        }

  setObject(updatedObject)

 },[question,questionAnswers,questionType,questionTypeString])


 useEffect(()=>{
  const existingObjectIndex = data.findIndex(obj => obj.id === object.id);
  console.log(existingObjectIndex);

  if (existingObjectIndex == -1) {
    setData(prevArray => [...prevArray, object]);
  } else {
      setData(prevArray => {
        const updatedArray = [...prevArray];
        updatedArray[existingObjectIndex] = { ...prevArray[existingObjectIndex], object };
        return updatedArray;
      });
  }
 },[object])
}

尝试过的无效代码

// useEffect(()=>{

// const index = data.findIndex((i)=>i.id == object.id)
// console.log(index);
// if(index == -1){
//   setData([object])
// } else{
//   let newData = [...data]
//   newData = data[index] = object
//   setData(newData)
// }

// },[object])

问题根源

  1. ID生成逻辑错误:useState的初始值中crypto.randomUUID()仅在组件首次渲染时执行一次,后续组件更新不会重新生成新ID,导致所有更新的对象都共用同一个ID。
  2. 数组更新逻辑错误:原代码中{ ...prevArray[existingObjectIndex], object }会把整个object作为子属性嵌套进去,而非合并对象属性。
  3. 不必要的state更新:通过useEffect更新object state会触发额外的渲染,且依赖项包含questionTypeString(ref对象,不会触发更新),逻辑冗余。

修复方案

核心调整点:

  • 用useRef存储唯一ID,确保组件生命周期内仅生成一次。
  • 用useMemo实时计算当前编辑的对象,避免冗余的state更新。
  • 简化数组更新逻辑,直接替换对应项而非嵌套合并。

修正后的代码

function CreateQuestionSurvey({data, setData}) {
  const [questionType, setQuestionType] = useState("");
  const questionTypeString = useRef();
  const [question, setQuestion] = useState("");
  const [questionAnswers, setQuestionAnswers] = useState();

  // 首次渲染生成唯一ID,useRef确保不会重复生成
  const objectId = useRef(crypto.randomUUID());

  // 实时计算当前编辑的对象,useMemo避免不必要的重复计算
  const currentObject = useMemo(() => ({
    question,
    type: questionTypeString.current?.value,
    possibleAnswers: questionAnswers,
    id: objectId.current
  }), [question, questionAnswers]);

  useEffect(() => {
    const existingIndex = data.findIndex(obj => obj.id === objectId.current);
    
    if (existingIndex === -1) {
      // 对象不存在,添加到数组
      setData(prev => [...prev, currentObject]);
    } else {
      // 对象已存在,替换对应位置的项
      setData(prev => prev.map((item, idx) => 
        idx === existingIndex ? currentObject : item
      ));
    }
  }, [currentObject, data, setData]);

  // 其他组件逻辑(如输入绑定等)
}

额外说明

如果是需要支持新增多个不同对象的场景,需在用户触发“新增”操作时才生成新ID(比如点击“添加问题”按钮时创建新的对象实例),而非组件初始化时生成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 22:52:43