How to toggle react-speech component outside of the div?

75 Views Asked by At
import React, { useState, useRef } from 'react';
import Speech from 'react-speech';

function MyComponent() {
  const [currentPlayingId, setCurrentPlayingId] = useState(null);
  const [isPlaying, setIsPlaying] = useState(false);
  const speechRef = useRef();



useEffect(() => {
           ...
              togglePlayPause(224)
            ...
            }
          }, [...]);


  const togglePlayPause = (id) => {
    if (currentPlayingId === id) {
      // If the clicked item is currently playing, pause it
      setIsPlaying(false);
    } else {
      // If another item (or no item) is playing, start the clicked item
      setCurrentPlayingId(id);
      setIsPlaying(true);
    }
  };

  return (
    <div>
      {items.map((item) => (
        <Speech
          ref={speechRef}
          key={item.id}
          onClick={() => togglePlayPause(item.id)}
          stop={!isPlaying || currentPlayingId !== item.id}
          pause={!isPlaying || currentPlayingId !== item.id}
          resume={isPlaying && currentPlayingId === item.id}
          lang="en-GB"
          textAsButton="Speak"
        />
      ))}
    </div>
  );
}

I want to trigger the speech item not via onClick event but via useEffect. Why is this code not working, I assume the way to go is to use ref differently. A usage of ref.current might be the solution.

Update: Turns out you can't trigger speech without the visitor clicking a button in chrome, which makes sense if I think about the yelling that awaited you when you clicked on a website back in the day.

1

There are 1 best solutions below

2
Anshu On

The Speech component features four buttons:- play, stop, pause, and resume. To utilize the button functionality, simply pass a value true to the corresponding prop of the Speech component.

You can easily change the audio states (play, stop, pause, resume) by clicking on the respective buttons, no need for useEffect or useRef hooks.

Here is the basic implementation of react-speech, following the idiomatic approach.

SpeechItem.js

import Speech from "react-speech";
import { style } from "./speechStyles";
export const SpeechItem = ({ text }) => (
  <Speech
    styles={style}
    pause
    resume
    stop
    lang="en-GB"
    text={text}
    textAsButton
  />
);

TextToSpeech.js

import React, { useState, useRef, useEffect } from "react";

import { SpeechItem } from "./SpeechItem";

export const TextToSpeech = ({ items }) => {
  return (
    <div>
      {items.map((item, index) => (
        <SpeechItem key={item.id} text={item.text} />
      ))}
    </div>
  );
};

SpeechStyles.js

const buttonStyle = {
  cursor: "pointer",
  pointerEvents: "none",
  outline: "none",
  backgroundColor: "Gainsboro",
  border: "solid 1px rgba(255,255,255,1)",
  borderRadius: 6,
};

export const style = {
  container: {
    width: "100%",
    height: "auto",
    display: "flex",
    flexDirection: "column",
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "#282c34",
    color: "white",
    padding: "1em",
  },
  text: {
    fontSize: "1.5em",
    fontWeight: "bold",
    textAlign: "center",
  },
  buttons: {
    display: "flex",
    flexDirection: "row",
    justifyContent: "space-around",
    width: "100%",
    marginTop: "1em",
  },
  play: {
    hover: {
      backgroundColor: "LightSkyBlue",
    },
    button: {
      ...buttonStyle,
      backgroundColor: "DodgerBlue",
    },
  },
  pause: {
    hover: {
      backgroundColor: "LightSalmon",
    },
    button: {
      ...buttonStyle,
      backgroundColor: "Tomato",
    },
  },
  stop: {
    hover: {
      backgroundColor: "LightCoral",
    },
    button: {
      ...buttonStyle,
      backgroundColor: "FireBrick",
    },
  },
  resume: {
    hover: {
      backgroundColor: "LightGreen",
    },
    button: {
      ...buttonStyle,
      backgroundColor: "ForestGreen",
    },
  },
};

If you wanna play around with the code