HumeAI / empathic-voice-api-js

Packages for using EVI with JavaScript, React, or as a Widget
https://empathic-voice-api-js-next-app.vercel.app
16 stars 10 forks source link

Infinite re-rendering caused by calling `useVoice()` #288

Open lasryaric opened 3 days ago

lasryaric commented 3 days ago

Hi, I found that there is an infinite re-rendering in my component as soon as I called useVoice().

Here is a very simple code that create this infinite re-rendering, I am using "@humeai/voice-react": "0.1.18".

/components/chat_with_voice.tsx

"use client";

import { useVoice, VoiceProvider } from "@humeai/voice-react";
import { Message } from "ai";
import { Chat } from "@/components/chat";
import { VoiceTest } from "./voice_test";

export function ChatWithVoice({
  accessToken,
}: {
  initialMessages: Array<Message>;
  selectedModelId: string;
  accessToken: string;
}) {
  return (
    <VoiceProvider
      configId="...."
      auth={{ type: "accessToken", value: accessToken }}
    >
      <VoiceTest />
    </VoiceProvider>
  );
}

/components/voice_test.tsx

import { useVoice } from "@humeai/voice-react";
import { Button } from "./ui/button";
import { useEffect } from "react";

export function VoiceTest() {
  const { status, connect, mute, muteAudio } = useVoice();
  console.log("rendering ************");
  useEffect(() => {
    muteAudio();
    mute();
  }, [mute, muteAudio]);
  return (
    <div>
      <Button onClick={() => connect()}>Connect</Button>
      <div>{status.value}</div>
    </div>
  );
}

I even called muteAudio() and mute() to make sure the re-rendering is not triggered by the micFft or fft values changing.

The React profiler shows that the VoiceTest component is re-rendering because the VoiceProvider context provider had hook 77 change. This only happens once I call the connect() function. After that, I don't do anything and I can observe a lot of rendering******** logs in my console. Please see attached screenshot for the profiler recording.

Screenshot 2024-11-20 at 17 58 26

Please let me know how we can fix that and how I can help.

lasryaric commented 3 days ago

So reading the Discord, I understand that you think is expected, but the problem I have then is that I can't have a component that calls connect() on mount and disconnect() on un-mout, which I think should work:

The following implementation connects and disconnects in an infinite loop, even though this is the recommended way of cleaning up resources and side effects in a React componenent.

import { useVoice } from "@humeai/voice-react";
import { Button } from "./ui/button";
import { useEffect } from "react";

export function VoiceTest() {
  const { status, connect, disconnect } = useVoice();
  console.log("rendering ************");
  useEffect(() => {
    connect();

    return () => {
      disconnect();
    };
  }, [connect, disconnect]);

  useEffect(() => {
    console.log("status", status.value);
  }, [status]);

  return (
    <div>
      <div>{status.value}</div>
    </div>
  );
}