1

I'm trying to code a chatbot interface using React hooks and Wit.ai.

I have tried setting the messages imperatively (setMessages([...messages, currentValue]) but that doesn't work either. Here's the code:

const [currentValue, setCurrentValue] = useState('');
const [messages, setMessages] = useState([]);


const handleChange = (event) => {
    setCurrentValue(event.target.value); // handling input change
}

const sendMessage = (event) => {
    event.preventDefault();
    if (currentValue.trim() !== '' || currentValue.trim().length > 1) {
        witClient.message(currentValue).then(data => {
            setMessages(() => [...messages, {text: currentValue, sender: 'user'}]); // here i set the user message
            if (data.entities) {
                setMessages(() => [...messages, {text: 'message from bot', sender: 'bot'}]); // this line seems to overwrite the user message with the bot message
                setCurrentValue('');
            }
        });
    }
    document.querySelector('input').focus();
}

When I handle the bots response it overwrites the users message.

voiys
  • 269
  • 5
  • 14

2 Answers2

1

Since you are relying on prior values you can use functional pattern for setting state like below:

Docs: https://reactjs.org/docs/hooks-reference.html#functional-updates

        setMessages((priorMessages) => [...priorMessages, {text: currentValue, sender: 'user'}]);
======================================
        if (data.entities) {
            setMessages((priorMessages) => [...priorMessages, {text: 'message from bot', sender: 'bot'}]);
Rikin
  • 5,351
  • 2
  • 15
  • 22
  • i didn't know about this, should probably check out the docs. thanks! – voiys Sep 03 '19 at 13:34
  • Lesser known feature as its not published in the guide but rather digged in somewhere, just found it: https://reactjs.org/docs/hooks-reference.html#functional-updates – Rikin Sep 03 '19 at 13:38
0

When you access messages after the if statement you're actually overwritting the first changes, cause [...messages, {text: currentValue, sender: 'user'}] will only be reflected in the next render. Set your changes all at once to prevent this

const sendMessage = (event) => {
    event.preventDefault();
    if (currentValue.trim() !== '' || currentValue.trim().length > 1) {
        witClient.message(currentValue).then(data => {
            let newMessages = [...messages, {text: currentValue, sender: 'user'}]
            if (data.entities) {
                newMessages = newMessages.concat({text: 'message from bot', sender: 'bot'})
                setCurrentValue('');
            }
            setMessages(messages)
        });
    }
    document.querySelector('input').focus();
}
Dupocas
  • 20,285
  • 6
  • 38
  • 56