react-chatbot-kit
react-chatbot-kit copied to clipboard
Displaying the message Loading .....
Hello Fredrik, I want to show the loading in bot message before I receive the message from the backend. i tried to show the loading in bot message with "loading:true" . But this is not working . Please help me .
Thanks
Shubhnam Kumar
any update on this ?
I need this too. I don't want to manually add a new spinner component
^ +1 agreed @FredrikOseberg
Also trying to figure out how to make this ... in the message show however long I want it to while I do an async Action. Any advise @FredrikOseberg ?
Any update?
In our case, the solution was to move the slow api request out of the MessageParser
into the ActionProvider
and create (createChatBotMessage('')
and append the new empty before the api call is made. Does that help in your case as well @kikychow ?
@clemenspeters Hi, thank you for your response. I am trying to create an empty bot message before the API call. I would like to ask how did you update the message after a response is returned from the API call? Thanks!
This will be super useful when the backend api call takes few seconds... Any suggestion on how to make the loading status in the bot message?
It is unfortunate that having more control over the loader isn't possible.
A workaround I implemented is to immediately post a chatbot message that a response was being crafted. Then, when the actual response is ready I replace the "Formulating a response" message with it.
Not ideal, but in some ways helpful to be able to show the user text that could help them know how long they'll be waiting.
Also trying to figure out how to make this ... in the message show however long I want it to while I do an async Action. Any advise @FredrikOseberg ?
HI All, So I found a Solution for this. The basic logic behind the solution is to create a dummy message just before the API call. & Render a loader instead of dummy message Till API response is pending. Remove the dummy message once API call is fulfilled.
Below are the accurate steps to do so.
-
Create custom bot Response message component (Refer here )
-
Create a constant DUMMY_MESSAGE = <ANY_UUID>
-
Pull out your API call from Message parser to Action provider & send the API call through
clientMessage
function in Action provider. This same function is accessible in message parser. -
Whenever user sends a message, in action provider, just before API call send that dummy message (which we kept in constants as shown below) this.greet({ message: DUMMY_MESSAGE }); // I am using message object due to some reason, you can use string too
-
Your clientMessage function in action provider will look like this
clientMessage = async (clientMessage) => {
this.addMessageToState(clientMessage);
const data = {
payloadName: clientMessage,
};
try {
this.greet({ message: DUMMY_MESSAGE }); // I am using message object, you can use string too
const apiResp = await apiCall(data);
if (apiResp.status == 200) {
this.greet({message : apiResp?.data?.response}, true); // Sending true as second parameter as i need to stop loading that chat object response once API call is finished. Will discuss it further in next steps
} else {
this.greet({
message: 'FAIL_TO_ANSWER',
}, true);
}
} catch {
this.greet({
message: 'FAIL_TO_ANSWER',
}, , true);
}
};
-
In that component (step 1) style your text as you want, and apply a condition, if message === DUMMY_MESSAGE, show bouncing loader instead of instead of dummy message (Refer this).
-
Add one method in your Action provider below. This will remove your loader message by updating state and adding API response message here.
removeLoadingMessage = (prevstateArray, removeLoading) => {
if (removeLoading) {
prevstateArray?.messages?.splice(
prevstateArray?.messages?.findIndex(
(a) => a?.message?.message === DUMMY_MESSAGE
),
1
);
return prevstateArray;
} else {
return prevstateArray;
}
};
- Update your addMessageToState by below. The parameter
removeLoading
will be by default false
addMessageToState = (message, removeLoading = false) => {
this.setState((prevstate) => ({
...this.removeLoadingMessage(prevstate, removeLoading),
messages: [...prevstate.messages, message],
}));
};
- Update your greet method as below
greet = (botMessage, removeLoading = false) => {
const message = this.createChatBotMessage(botMessage);
this.addMessageToState(message, removeLoading);
};
You should be good to go now.
I found a solution to this problem. Please create a new file called "Loader.js" and then add the following code:
import React from 'react';
const Loader = () => {
return (
<div className='chatbot-loader-container'>
<svg
id='dots'
width='50px'
height='21px'
viewBox='0 0 132 58'
version='1.1'
xmlns='http://www.w3.org/2000/svg'
>
<g stroke='none' fill='none'>
<g id='chatbot-loader' fill='#fff'>
<circle id='chatbot-loader-dot1' cx='25' cy='30' r='13'></circle>
<circle id='chatbot-loader-dot2' cx='65' cy='30' r='13'></circle>
<circle id='chatbot-loader-dot3' cx='105' cy='30' r='13'></circle>
</g>
</g>
</svg>
</div>
);
};
export default Loader;
Now, if it's loading, use this loader. It's the same loader from the react-chatbot-kit, so you won't notice any difference. You don't have to add any CSS, but please don't change anything in this file.
Thanks @nikunjmishra81 , that helped me out. It's a bit hacky though. I feel there needs to be some kind of loading state on the chatbot which you could set pre and post API call and some kind of loader icon or message is shown which isn't an actual chatbot message. Being able to customize the loader icon would be helpful too.
Had anyone found an easy way to handle this? Ideally, I would like to see the standard chatbot loader with dots appear until the backend responds. Right now, the client just sits there for 10 seconds until the backend provides the answer.
In our case, the solution was to move the slow api request out of the
MessageParser
into theActionProvider
and create (createChatBotMessage('')
and append the new empty before the api call is made. Does that help in your case as well @kikychow ?
@clemenspeters I was hoping you could clarify how you got this working? I started going down this path but I still get nothing until the API call is done which takes 2-7 seconds so I really would like to have the loader appear while the call is happening.
`class ActionProvider { constructor(createChatBotMessage, setStateFunc) { this.createChatBotMessage = createChatBotMessage; this.setState = setStateFunc; }
async helloWorldHandler(inputmes) { this.createChatBotMessage(''); const airesults = await ( await fetch (...) .... some cleanup var message = this.createChatBotMessage(<div dangerouslySetInnerHTML={{ __html: finalresult }} />); this.setChatbotMessage(message);` }
setChatbotMessage = (message) => { this.setState(state => ({ ...state, messages: [...state.messages, message] })) } }`
Very simple solution to this problem. The idea is that you setState with createChatBotMessage(<Loader />) before API fetch. When the fetch is complete you just remove the last state message (yes I am well aware that if user submits again this will remove their message but...) Code below
const handleBotApi = async (usrMsg) => {
// Add Loading before API call
const loading = createChatBotMessage(<Loader />)
setState((prev) => ({ ...prev, messages: [...prev.messages, loading], }))
const botRes = await postAPI('/message', usrMsg)
// Stop Loading after call is returned
const botMessage = createChatBotMessage(botRes.bot)
setState((prev) => {
// Remove Loading here
const newPrevMsg = prev.messages.slice(0, -1)
return { ...prev, messages: [...newPrevMsg, botMessage], }
})
}
Very simple solution to this problem. The idea is that you setState with createChatBotMessage() before API fetch. When the fetch is complete you just remove the last state message (yes I am well aware that if user submits again this will remove their message but...) Code below
const handleBotApi = async (usrMsg) => { // Add Loading before API call const loading = createChatBotMessage(<Loader />) setState((prev) => ({ ...prev, messages: [...prev.messages, loading], })) const botRes = await postAPI('/message', usrMsg) // Stop Loading after call is returned const botMessage = createChatBotMessage(botRes.bot) setState((prev) => { // Remove Loading here const newPrevMsg = prev.messages.slice(0, -1) return { ...prev, messages: [...newPrevMsg, botMessage], } }) }
@jacobcravinho Thanks so much, I was able to get it working using your example!
@jacobcravinho but this solution causing the chatbox to flicker once received reponse from API , then display loading again and then show message.