reactjs React -元素随useState消失

xyhw6mcr  于 2023-04-20  发布在  React
关注(0)|答案(2)|浏览(166)

我正在尝试学习React,并使用OpenAI API构建一个简单但专业的聊天机器人。我目前能够发送和接收消息,但在显示消息时遇到了一个问题。当我发送用户消息时,用户消息将显示在页面上,但只有在响应到达时,用户消息才会消失。
我的Chat组件如下所示。我的猜测是setMessages([...messages, botMessage]);只是在当前消息列表的状态后面附加了一条消息,尽管我可能误解了其中的一些内容。

import React, { useState } from "react";
import { PaperAirplaneIcon } from "@heroicons/react/20/solid";
import axios from "axios";
import UserMessage from "./UserMessage";
import BotMessage from "./BotMessage";

const Chat = () => {
  const [messages, setMessages] = useState([]);
  const [inputValue, setInputValue] = useState("");
  const [loading, setLoading] = useState(false);
  const [rules, setRules] = useState([]);

  const handleInputSubmit = async (e) => {
    e.preventDefault();
    setLoading(true);
    const userMessage = { type: "user", text: inputValue };
    setMessages([...messages, userMessage]);
    setInputValue("");
    const botMessage = await getBotMessage(inputValue);
    setMessages([...messages, botMessage]);
    setLoading(false);
  };

  const getBotMessage = async (userMessage) => {
    try {
      const response = await axios.post("http://<url>/api/chat", {
        message: userMessage,
      });
      console.log("response", response.data);
      const botMessage = { type: "bot", text: response.data.response };
      return botMessage;
    } catch (e) {
      console.log(e);
      const botMessage = {
        type: "bot",
        text: "Something went wrong. Try again.",
      };
      return botMessage;
    }
  };

  return (
    <div className="flex flex-col items-center w-full h-full justify-between">
      <h1 className="text-3xl font-bold my-5">Chatbot</h1>
      <div className="w-full">
        {messages.map((message, index) => {
          if (message.type === "user") {
            return <UserMessage key={index} text={message.text} />;
          }
          return <BotMessage key={index} text={message.text} />;
        })}
        <form
          onSubmit={handleInputSubmit}
          className="flex flex-row w-full mb-5 mt-2"
        >
          <input
            className="border-2 rounded-md p-2 w-full"
            type="text"
            value={inputValue}
            onChange={(e) => setInputValue(e.target.value)}
          />
          <button type="submit">
            <PaperAirplaneIcon className="w-6 h-6 text-green-500" />
          </button>
        </form>
      </div>
    </div>
  );
};

export default Chat;
yqhsw0fo

yqhsw0fo1#

你可以在这里的官方文档中找到解释:
set函数只为下一次渲染更新状态变量。如果你在调用set函数后读取状态变量,你仍然会得到调用前屏幕上的旧值。
调用setMessages不会导致message变量立即更新。如果你仔细想想,这是完全有意义的,因为messages被定义为const,所以它永远不能被重新分配!在下一次重新渲染时,你将拥有一个新的messages,其值已更新。
因此,对setMessages的第二次调用是将botMessage添加到原始数组中,有效地替换了userMessage
您可以尝试使用更新器函数,如:

setMessages(prevState => [...prevState, userMessage]);
...
setMessages(prevState => [...prevState, botMessage]);

Updater函数也会在下一次重新渲染时执行,但它们是在队列中应用的,并且总是接收状态变量的最新值,因此这两个元素都将被正确添加。

velaa5lx

velaa5lx2#

编辑:下面的解决方案可以,但不是最优方案,请查看其他答案。

作为React的新手,我不明白为什么会这样,但我找到了答案。
由于某种原因,setMessages([...messages, botMessage]);无法看到setMessages([...messages, userMessage]);在三行之前(当发送用户消息时)给出的更新后的messages状态数组。
解决方案是添加这两条消息,当bot消息到达时,如,因此handleInputSubmit变为:

const handleInputSubmit = async (e) => {
    e.preventDefault();
    setLoading(true);
    const userMessage = { type: "user", text: inputValue };
    setMessages([...messages, userMessage]);
    setInputValue("");
    const botMessage = await getBotMessage(inputValue);
    setMessages([...messages, userMessage, botMessage]); // <-- This fixes it.
    setLoading(false);
  };

如果有人能解释或提供一个链接到文档解释这一点,我将非常感谢。

相关问题