Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React setstate can only update a mounted or mounting component -- on rerender

I am using the react-speech-recognition package to do speech-to-text in my app.

Inside render of app.js:

            <ChatContainer
              micActive={this.state.micActive}
              sendData={this.sendData}
              makeInactive={this.makeInactive}
            >
                <SpeechToText>
                    sendData={this.sendData}
                    makeInactive={this.makeInactive}
                    micActive={this.state.micActive}
                </SpeechToText>

                  <div>
                      <button
                        id="micInactive"
                        type="button"
                        onClick={this.makeActive}
                      />
                  </div>

            </ChatContainer>

As you can see above, my ChatContainer has two Children :

  1. SpeechToText

  2. div that contains a button

SpeechToText.js :

class SpeechToText extends Component {

    componentWillReceiveProps(nextProps) {
        if (nextProps.finalTranscript && nextProps.micActive) {
            this.props.sendData(nextProps.finalTranscript);
            this.props.resetTranscript();
            this.props.makeInactive();
        }
    }

    render() {
        return (
            <div>
                <button
                  id="micActive"
                  type="button"
                />
            </div>
        );
    }
}

export default SpeechRecognition(SpeechToText);

SpeechToText receives the speech recognition props from Speech Recognition

ChatContainer.js

const ChatContainer = props => (

    <div>
        {
             React.Children.map(props.children, (child, i) => {
                 if (i === 0 && child.props.active) {
                     return React.cloneElement(child, {
                         sendData: props.sendData,
                         makeInactive: props.makeInactive,
                         micActive: props.micActive,
                     });
                 }

                 if (i === 1 && child.props.inactive) {
                     return child;
                 }
                 return null;
             })
        }
    </div>
);

export default connect()(ChatContainer);

Finally ChatContainer decides which child to render. If the state is inactive render the div with the inactive button.

EDIT

By default the state in inactive -- this.state.micActive: false. If the state is inactive I render the <div> with the button. If that button is clicked the makeActive method gets called and makes the state active -- if the state is active I render <SpeechToText>. Once I complete the voice-to-text I call makeInactive -- that makes the state inactive and the <div> is rendered once again

The first time I click the button SpeechToText gets rendered and voice-to-text works.

However the second time I click the button -- And I try to rerender the SpeechToText component I get an error:

setstate can only update a mounted or mounting component

Sometimes the error does not appear but the voice-to-text does not work.

Why is this happening - Do I need to force remove the component perhaps?

like image 324
user2456977 Avatar asked Feb 04 '26 03:02

user2456977


1 Answers

Turns out it was an issue with the SpeechRecognitionContainer. The package was updated with new props and configuration options and I resolved my issue.

You can read more about react-speech-recognition here.

Now simply I can render the component like so:

render() {
    return (
        <SpeechToText
          sendSpeechToText={this.sendSpeechToText}

        />
    );
}

and SpeechToText looks something likes this:

class SpeechToText extends Component {

    constructor(props) {
        super(props);

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

    componentWillReceiveProps(nextProps) {
        if (nextProps.finalTranscript && nextProps.micActive) {
            this.props.sendSpeechToText(nextProps.finalTranscript);
            this.props.resetTranscript();
            this.props.stopListening();
        }
    }

    componentWillUnmount() {
        if (this.props.listening) {
            this.props.abortListening();
        }
    }

    reactivate() {
        if (!this.props.listening) {
           this.props.startListening();
    }

    render() {
        return (
            <div>
                <button
                  id="micButton"
                  type="button"
                  onClick={this.reactivate}
                />
            </div>
        );
    }
}

const options = {
  autoStart: false
}

export default SpeechRecognition(options)(SpeechToText)
like image 110
user2456977 Avatar answered Feb 06 '26 17:02

user2456977