DeveloperLV
DeveloperLV

Reputation: 1781

How to pass a value from a function to a class in React?

Goal

I am aiming to get the transcript value, from the function Dictaphone and pass it into to the SearchBar class, and finally set the state term to transcript.

Current code

import React from 'react';
import SpeechRecognition, { useSpeechRecognition } from 'react-speech-recognition';

const Dictaphone = () => {
    const { transcript } = useSpeechRecognition()

    if (!SpeechRecognition.browserSupportsSpeechRecognition()) {
        return null
    }

    return (
        <div>
            <button onClick={SpeechRecognition.startListening}>Start</button>
            <p>{transcript}</p>
        </div>
    )
}



class SearchBar extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            term: ''
        }

        this.handleTermChange = this.handleTermChange.bind(this);
    }

    handleTermChange(event) {
        this.setState({ term: event.target.value });
    }


    render() {
        return (
            <div className="SearchBar">
                <input onChange={this.handleTermChange} placeholder="Enter some text..." />
                <Dictaphone />
            </div>
        )
    }
}

export { SearchBar };

Problem

I can render the component <Dictaphone /> within my SearchBar. The only use of that is it renders a button and the transcript. But that's not use for me.

What I need to do is, get the Transcript value and set it to this.state.term so my input field within my SearchBar changes.

What I have tried

I tried creating an object within my SearchBar component and called it handleSpeech..

class SearchBar extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            term: ''
        }

        this.handleTermChange = this.handleTermChange.bind(this);
    }


    handleTermChange(event) {
        this.setState({ term: event.target.value });
    }

    handleSpeech() {
        const { transcript } = useSpeechRecognition()

        if (!SpeechRecognition.browserSupportsSpeechRecognition()) {
            return null
        }

        SpeechRecognition.startListening();

        this.setState({ term: transcript});
    }


    render() {
        return (
            <div className="SearchBar">
                <input onChange={this.handleTermChange} placeholder="Enter some text..." />
                <button onClick={this.handleSpeech}>Start</button>
            </div>
        )
    }
}

Error

But I get this error:

React Hook "useSpeechRecognition" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function react-hooks/rules-of-hooks React Hooks must be called in a React function component or a custom React Hook function

Upvotes: 1

Views: 319

Answers (2)

mcy
mcy

Reputation: 291

Well, the error is pretty clear. You're trying to use a hook in a class component, and you can't do that.

Option 1 - Change SearchBar to a Function Component

If this is feasible, it would be my suggested solution as the library you're using appears to be built with that in mind.

Option 2

Communicate between Class Component <=> Function Component.

I'm basing this off your "current code".

import React, { useEffect } from 'react';
import SpeechRecognition, { useSpeechRecognition } from 'react-speech-recognition';

const Dictaphone = ({ onTranscriptChange }) => {
  const { transcript } = useSpeechRecognition();

  // When `transcript` changes, invoke a function that will act as a callback to the parent (SearchBar)
  // Note of caution: this code may not work perfectly as-is. Invoking `onTranscriptChange` would cause the parent's state to change and therefore Dictaphone would re-render, potentially causing infinite re-renders. You'll need to understand the hook's behavior to mitigate appropriately.
  useEffect(() => {
    onTranscriptChange(transcript);
  }, [transcript]);
    
  if (!SpeechRecognition.browserSupportsSpeechRecognition()) {
    return null
  }

  return (
    <div>
      <button onClick={SpeechRecognition.startListening}>Start</button>
      <p>{transcript}</p>
    </div>
  )
}

class SearchBar extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      transcript: ''
    }
    this.onTranscriptChange = this.onTranscriptChange.bind(this);
  }

  onTranscriptChange(transcript){
    this.setState({ transcript });
  }

  render() {
    return (
      <div className="SearchBar">
        <input onChange={this.handleTermChange} placeholder="Enter some text..." />
        <Dictaphone onTranscriptChange={onTranscriptChange} />
      </div>
    )
  }
}

Upvotes: 2

backtick
backtick

Reputation: 2775

useSpeechRecognition is a React hook, which is a special type of function that only works in specific situations. You can't use hooks inside a class-based component; they only work in function-based components, or in custom hooks. See the rules of hooks for all the limitations.

Since this hook is provided by a 3rd party library, you have a couple of options. One is to rewrite your search bar component to be a function. This may take some time if you're unfamiliar with hooks.

You can also see if the react-speech-recognition library provides any utilities that are intended to work with class-based components.

Upvotes: 1

Related Questions