skip to Main Content
import React, { useState, useEffect, useMemo } from 'react';
import axios from 'axios';
import { ChatLog } from './ChatLog.jsx';
import { GoArrowUp } from "react-icons/go";

export function QueryBar() {
    const [searchInput, setSearchInput] = useState("");
    const [botChat, setBotChat] = useState([]);
    const [userChat, setUserChat] = useState([]);

    const handleKeyDown = (e) => {
        if (e.key === 'Enter') {
            e.preventDefault();
            handleSubmit();
        }
    }
    const handleSubmit = () => {
        const params = {
            prompt: searchInput
        }
        axios.get("http://localhost:5555/chat", { params })
            .then((response) => {
                setBotChat(botChat => [...botChat, response.data.result]);
                setSearchInput("");
            })
            .catch((error) => {
                alert('Something bad happened while getting API response');
                console.log(error);
            })
    }
    useEffect(() => {
        setSearchInput(searchInput);
    }, [searchInput]);

    const chat = useMemo(() => botChat.map(chat => {
        return (
            <>
                <React.Fragment>
                    <h4 className="pl-7 pt-2">Bot: </h4>
                    <div className="pl-24 before:absolute before:inset-0 before:animate-typewriter before:bg-white after:absolute after:inset-0 after:w-[0.125em] after:animate-caret after:bg-black">{chat}</div>
                </React.Fragment>
            </>
        )
    }), [botChat])
    return (
        <>
        <div className="h-screen">
            <div>{chat}</div>
            <div className="p-4">
                <div className="w-screen absolute bottom-0 flex justify-center mb-8">
                    <form className="w-1/2 rounded-lg outline">
                        <input className="w-full placeholder:text-gray-500 pl-[8px] outline-none" type="text" placeholder='Talk to Bot'
                        onChange={(e) => setSearchInput(e.target.value)} onKeyDown={handleKeyDown} value={searchInput}/>
                    </form>
                    <button className="mx-4 h-6 w-6 inline-block rounded-full align-center outline items-center" onClick={handleSubmit}>
                        <div className='flex items-center justify-center'>
                            <GoArrowUp/>
                        </div>
                    </button>
                </div>
            </div>
        </div>
        </>
    )
    }

export default QueryBar

Seems like every time the botChat state array is updated by the API call, it rerenders the entire chat log as the animation occurs for all previous chats as well. How can I fix this? I tried to use useMemo hook but it seems like it doesn’t work or I’m just using it wrong (probably the latter).

2

Answers


  1. useMemo wont work in this cases since you are updating the chat state with new values. Also this issue is created since you are storing the mapped values and then rendering them so every time the chat state will be updated your whole component will re render

    Rather just render the mapped values directly like below

    export function QueryBar() {
    const [searchInput, setSearchInput] = useState("");
    const [botChat, setBotChat] = useState([]);
    const [userChat, setUserChat] = useState([]);
    
    const handleKeyDown = (e) => {
        if (e.key === 'Enter') {
            e.preventDefault();
            handleSubmit();
        }
    }
    const handleSubmit = () => {
        const params = {
            prompt: searchInput
        }
        axios.get("http://localhost:5555/chat", { params })
            .then((response) => {
                setBotChat(botChat => [...botChat, response.data.result]);
                setSearchInput("");
            })
            .catch((error) => {
                alert('Something bad happened while getting API response');
                console.log(error);
            })
    }
    
    useEffect(() => {
        setSearchInput(searchInput);
    }, [searchInput]);
    
    return (
        <div className="h-screen">
            <div>
                {botChat.map((chat, index) => (
                    <React.Fragment key={index}>
                        <h4 className="pl-7 pt-2">Bot: </h4>
                        <div className="pl-24 before:absolute before:inset-0 before:animate-typewriter before:bg-white after:absolute after:inset-0 after:w-[0.125em] after:animate-caret after:bg-black">
                            {chat}
                        </div>
                    </React.Fragment>
                ))}
            </div>
            <div className="p-4">
                <div className="w-screen absolute bottom-0 flex justify-center mb-8">
                    <form className="w-1/2 rounded-lg outline">
                        <input className="w-full placeholder:text-gray-500 pl-[8px] outline-none" type="text" placeholder='Talk to Bot'
                            onChange={(e) => setSearchInput(e.target.value)} onKeyDown={handleKeyDown} value={searchInput} />
                    </form>
                    <button className="mx-4 h-6 w-6 inline-block rounded-full align-center outline items-center" onClick={handleSubmit}>
                        <div className='flex items-center justify-center'>
                            <GoArrowUp />
                        </div>
                    </button>
                </div>
            </div>
        </div>
    )
    }
    
    Login or Signup to reply.
  2. Provide a key to each item so the corresponding DOM elements can stay the same and only new items will create new DOM elements.

    botChat.map(chat => (
      <React.Fragment key={chat}>
        <h4 className="...">Bot: </h4>
        <div className="...">{chat}</div>
      </React.Fragment>
    ))
    

    That said, your component code contains alot of unnecessairy lines.
    You don’t need to wrap everthing in <></> fragments, this is only needed if you return more than one top-level node.
    You don’t need to update searchInput with a useEffect.
    Your useMemo is not needed here.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search