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