Search code examples
reactjsonclicktext-to-speecharrow-functions

Is it possible to write this a shorter way in React using onClick?


Right now, my code is working as intended, but I wanted to know if there was a shorter way of writing this. I'm using speaktts in React which consists of a const of what I want the text to be spoken through the text to speech. I have a function to handleClick and then the user would have to click on the button to hear the word. If the user clicks on the sound emoji, they will get to hear apple, banana, and carrot. Is there any way that I can make this shorter?


import React from "react";
import Speech from "speak-tts";

function Alphabet() {
  const [say1] = React.useState("apple");
  const [say2] = React.useState("banana");
  const [say3] = React.useState("carrot");
  const speech = new Speech();
  speech
    .init({
      lang: "en-US",
      rate: 0.4,
    })
    .then((data) => {
      console.log("Speech is ready, voices are available", data);
    })
    .catch((e) => {
      console.error("An error occured while initializing : ", e);
    });

  const handleClick1 = () => {
    speech.speak({
      text: say1,
    });
  };

  const handleClick2 = () => {
    speech.speak({
      text: say2,
    });
  };

  const handleClick3 = () => {
    speech.speak({
      text: say3,
    });
  };
  return (
    <>

          <h2>Apple</h2>
          <button
            value="Apple"
            onClick={handleClick1}
            alt="click here for pronounciation"
            className="buttonSound"
          >
            🔊
          </button>

          <h2>Banana</h2>
          <button
            value="Banana"
            onClick={handleClick2}
            alt="click here for pronounciation"
            className="buttonSound"
          >
            🔊
          </button>

          <h2>Carrot</h2>
          <button
            value="Carrot"
            onClick={handleClick3}
            alt="click here for pronounciation"
            className="buttonSound"
          >
            🔊
          </button>


    </>
  );
}

export default Alphabet;

Solution

  • Turn the <h2> and <button>s into their own component. It looks like the only value that changes is the header text, which is also the value for the button, which is also the text passed to .speak on click. There is no need for state for the text because the text doesn't change.

    So, pass down the speech object and the text as props.

    You also should not be calling new Speech every time the component renders. Create it only a single time instead, with a ref or state.

    const Word = ({ text, speech }) => (
        <>
            <h2>{text}</h2>
            <button
                value={text}
                onClick={() => speech.speak({ text })}
                alt="click here for pronounciation"
                className="buttonSound"
            >
                🔊
            </button>
        </>
    );
    
    function Alphabet() {
        const [speech] = useState(() => new Speech());
        useEffect(() => {
            speech
                .init({
                    lang: "en-US",
                    rate: 0.4,
                })
                .then((data) => {
                    console.log("Speech is ready, voices are available", data);
                })
                .catch((e) => {
                    console.error("An error occured while initializing : ", e);
                });
        }, []);
    
        return (
            <>
                <Word text="Apple" speech={speech} />
                <Word text="Banana" speech={speech} />
                <Word text="Carrot" speech={speech} />
            </>
        );
    }