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

Next.js/React状态数组两次追加值被覆盖问题求助

问题:ChatGPT聊天机器人状态数组更新异常,AI回复覆盖用户消息

开发Next.js/React简易ChatGPT聊天机器人时,点击发送按钮后,用户输入消息本应先加入状态数组,再追加ChatGPT的API回复,但实际AI回复会覆盖用户消息,仅显示后者。怀疑是闭包导致状态更新引用旧数组,且React状态更新为异步,搜索后未解决。相关代码如下:

import {useState} from "react";

export default function Chatbot() {
    const [inputMessage, setInputMessage] = useState('');
    const [messages, setMessages] = useState([]);

    /**
     * Push a new message to array of messages
     * @param {string} text
     */
    const addMessage = (text) => {
        setMessages([
            ...messages,
            text,
        ])
    }

    const queryChatbot = () => {
        // Add input message / question as new message
        addMessage(inputMessage);

        fetch('/api/chatbot', {
            method: 'post',
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                inputMessage,
            }),
        })
            .then(response => response.json())
            .then(data => {
                if (data.response) {
                    // For successful response: Add response as new message
                    addMessage(data.response.output.response);
                } else {
                    // Otherwise add error as new message
                    addMessage('Sorry, no response possible.');
                }
            })
            .catch(error => {
                // In error case we add a new message with an error
                addMessage('Sorry, an error ocurred.');
            });
    }

    return <>
        <input type="text" placeholder="Send a message" onChange={(event) => setInputMessage(event.target.value)} />
        <button onClick={queryChatbot}>Send message</button>
        {messages.map(message => (
            <p>{ message }</p>
        ))}
    </>
}

原因分析

问题核心在于React状态更新的异步性和闭包捕获旧值:

  • addMessage函数中直接使用当前渲染周期的messages状态值生成新数组
  • 调用queryChatbot时,先执行addMessage(inputMessage),但React状态更新是异步的,messages不会立即更新
  • 后续fetch是异步操作,当回调执行时,queryChatbot闭包中捕获的messages仍是初始的旧值(空数组)
  • 第二次调用addMessage时,会基于旧的空数组生成新数组,直接覆盖第一次更新的结果,最终仅显示AI回复

解决方法

使用React状态更新的函数式更新方式,确保每次更新都基于最新的前一次状态,而非闭包中的旧值:

修改addMessage函数

将setMessages的参数改为函数,接收上一次状态prevMessages,基于它生成新数组:

const addMessage = (text) => {
    setMessages(prevMessages => [...prevMessages, text]);
}

额外优化:给列表项添加唯一key

React渲染列表时需要唯一key来优化性能、避免警告,修改map部分:

{messages.map((message, index) => (
    <p key={index}>{ message }</p>
))}

完整修改后的代码

import {useState} from "react";

export default function Chatbot() {
    const [inputMessage, setInputMessage] = useState('');
    const [messages, setMessages] = useState([]);

    const addMessage = (text) => {
        setMessages(prevMessages => [...prevMessages, text]);
    }

    const queryChatbot = () => {
        addMessage(inputMessage);

        fetch('/api/chatbot', {
            method: 'post',
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                inputMessage,
            }),
        })
            .then(response => response.json())
            .then(data => {
                if (data.response) {
                    addMessage(data.response.output.response);
                } else {
                    addMessage('Sorry, no response possible.');
                }
            })
            .catch(error => {
                addMessage('Sorry, an error occurred.');
            });
    }

    return <>
        <input type="text" placeholder="Send a message" onChange={(event) => setInputMessage(event.target.value)} />
        <button onClick={queryChatbot}>Send message</button>
        {messages.map((message, index) => (
            <p key={index}>{ message }</p>
        ))}
    </>
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 19:32:47