1

So amidst refactoring my class based chatbot component to use react hooks I came across a problem with the useState hook overwriting the object in the state. This lead to only the bot responses showing up in the UI. When I chat with the bot, a flash of the user input shows in the UI then is overwritten by the chatbots response. Here is the code:


export const Chatbot = () => {
  const [messages, setMessages] = useState([]);
  const [value, setValue] = useState("");

  async function df_text_query(text) {
    let says = {
      speaks: "me",
      message: {
        text: {
          text
        }
      }
    };
    setMessages([...messages, says]);

    const res = await axios.post("/api/df_text_query", {
      text,
      userID: cookies.get("userID")
    });

    // Handles fullfillment routes for dialogflow
    res.data.fulfillmentMessages.forEach(message => {
      says = {
        speaks: "bot",
        message
      };
      setMessages([...messages, says]);
    });
  }

  const handleChange = e => {
    setValue(e.target.value);
  };

  const handleSubmit = e => {
    e.preventDefault();
    if (value !== "") {
      const message = value.split();
      df_text_query(message);
    }
    setValue("");
  };

  const handleButtonSend = async event => {
    const eventText = event.target.innerText;
    await setValue(eventText);
    const message = value.split();
    await df_text_query(message);
    await setValue("");
  };

  return (
    <div>
      <div>chatbot code here</div>
    </div>
  );
};

Is it possible to write useState like this, twice within the same async function? If not how do you propose I refactor this code so that the messages state returns an array of alternating objects such as:

[{says: {
   speaks: "me",
   message: {
       text: {
          text
       }
    }
  }
},
{says: {
   speaks: "bot",
   message: {
      text: {
        text
      }
     }
   }
 },
{says: {
   speaks: "me",
   message: {
       text: {
          text
       }
    }
  }
},
{says: {
   speaks: "bot",
   message: {
      text: {
        text
      }
     }
   }
 }
]```

Any answer would be very much appreciated. I've been stuck on this problem for a while now. If you need more information I'm happy to provide!

Cheers,

Jacks


4

1 回答 1

1

尝试这样的事情:

 async function df_text_query(text) {
    let says = [{
      speaks: "me",
      message: {
        text: {
          text
        }
      }
    }];

    const res = await axios.post("/api/df_text_query", {
      text,
      userID: cookies.get("userID")
    });

    // Handles fullfillment routes for dialogflow
    let saysBatch = [says, ...res.data.fulfillmentMessages.map(message => ({
        speaks: "bot",
        message
      }))];
    setMessages([...messages, ...saysBatch]);
于 2020-01-24T02:12:19.070 回答