JamesBrill / react-speech-recognition

💬Speech recognition for your React app
https://webspeechrecognition.com/
MIT License
674 stars 120 forks source link

Error when using startListening #4

Closed kejtizuki closed 6 years ago

kejtizuki commented 6 years ago

Hi, I've added this in my code:

const propTypes = {
// Props injected by SpeechRecognition
  transcript: PropTypes.string,
  resetTranscript: PropTypes.func,
  startListening: PropTypes.func,
  browserSupportsSpeechRecognition: PropTypes.bool
}

I want to create the button which will enable speech recognition on click. I tried using the 'startListening' function but it's not working for me. I'm getting the error cannot read property 'setState' of undefined at startListening. Could you help me with that? I'm new to react so maybe it's just my mistake...

JamesBrill commented 6 years ago

I'd be happy to help. Can you share the code where you are using startListening?

kejtizuki commented 6 years ago
render (){
    const { transcript, resetTranscript, startListening, browserSupportsSpeechRecognition } = this.props;
    if (!browserSupportsSpeechRecognition) {
      return (<p>Your browser doesn't allow speech recognition</p>)
    }
    return(
      <div className="container">
        <button className="btnStart" onClick={startListening}>
          <img src="../../assets/microphone.svg" className="icon"/>
        </button>
        <input className="speechTranscript" onChange={this.handleChange.bind(this)} value={transcript}/>
        <div className="actions">
          <button className="btn">Stop</button>
          <button className="btn" onClick={resetTranscript}>Reset</button>
        </div>
      </div>
    )
  }

I tried doing something like this

JamesBrill commented 6 years ago

I have made a component that renders virtually the same as yours, but was unable to reproduce this error. A few more questions to help me determine the issue:

const propTypes = { // Props injected by SpeechRecognition transcript: PropTypes.string, startListening: PropTypes.func, stopListening: PropTypes.func, browserSupportsSpeechRecognition: PropTypes.bool }

class Dictaphone extends Component { render() { const { transcript, startListening, stopListening, browserSupportsSpeechRecognition } = this.props

if (!browserSupportsSpeechRecognition) {
  return null
}

return (
  <div>
    <button onClick={stopListening}>Stop</button>
    <button onClick={startListening}>Start</button>
    <span>
      {transcript}
    </span>
  </div>
)

} }

Dictaphone.propTypes = propTypes

export default SpeechRecognition(Dictaphone)

JamesBrill commented 6 years ago

Were you able to resolve this, @kejtizuki?

kejtizuki commented 6 years ago

Yeah actually if I use it without defining options it works, but if I want to use it with options:

const options = {
  lang : 'en-US',
  autoStart: false
}

export default SpeechRecognition(options)(Dictaphone)

Than it gives me this error. Sorry for late response but I just wasn't working on this earlier..

kejtizuki commented 6 years ago

And to answer your questions. Yes, I'm using setState in handleChange method. The error occurs when I click on button that should activate startListening method. Exact error looks like this:

bundle.js:61568 Uncaught TypeError: Cannot read property 'setState' of undefined at startListening (bundle.js:61568) at bundle.js:8912 at HTMLUnknownElement.boundFunc (bundle.js:16228) at Object.ReactErrorUtils.invokeGuardedCallback (bundle.js:16234) at executeDispatch (bundle.js:16016) at Object.executeDispatchesInOrder (bundle.js:16039) at executeDispatchesAndRelease (bundle.js:15694) at executeDispatchesAndReleaseTopLevel (bundle.js:15705) at Array.forEach () at forEachAccumulated (bundle.js:16335)

JamesBrill commented 6 years ago

I haven't been able to reproduce this so far. It's especially baffling that the error only occurs when passing in options. On that note, I can point out one thing you can fix. The only option that does anything is autoStart. If you want to change the lang, you can do this by taking the injected recognition object and setting the lang on it like so:

recognition.lang = 'en-US'

The error you see occurs when a class method isn't bound to any context (this is why you need to do things like this.foo.bind(this). If you're passing in my startListening as your onClick callback, then that error seems to be coming from the SpeechRecognition library. The startListening method does indeed call this.setState. However, I'm not sure why this is undefined in this case - I use a library called autobind that binds that method to the component's context.

Perhaps autobind gets confused about the component to bind to when higher-order components are involved. Or perhaps I've missed something really obvious. I'll keep investigating!

If I run out of ideas, I'll try replacing my autobind methods with arrow functions.

kejtizuki commented 6 years ago

Sorry I think I confused it a bit. I also get this error when I use the code that you put above, however (using the code from above from your comment) I don't get the error when I click on start but now I get it in stopListening.

Uncaught TypeError: Cannot read property 'setState' of undefined at stopListening (SpeechRecognition.js?fb07:188) at makeAssimilatePrototype.js?c7d8:15 at HTMLUnknownElement.boundFunc (ReactErrorUtils.js?dc41:63) at Object.ReactErrorUtils.invokeGuardedCallback (ReactErrorUtils.js?dc41:69) at executeDispatch (EventPluginUtils.js?5d8c:83) at Object.executeDispatchesInOrder (EventPluginUtils.js?5d8c:106) at executeDispatchesAndRelease (EventPluginHub.js?0f32:41) at executeDispatchesAndReleaseTopLevel (EventPluginHub.js?0f32:52) at Array.forEach () at forEachAccumulated (forEachAccumulated.js?e2c3:22)

If I use the same code with options I'm getting an error about startListening. And also if I try to use resetTranscript I;m getting the following error:

Uncaught TypeError: Cannot read property 'disconnect' of undefined at resetTranscript (SpeechRecognition.js?fb07:161) at makeAssimilatePrototype.js?c7d8:15 at HTMLUnknownElement.boundFunc (ReactErrorUtils.js?dc41:63) at Object.ReactErrorUtils.invokeGuardedCallback (ReactErrorUtils.js?dc41:69) at executeDispatch (EventPluginUtils.js?5d8c:83) at Object.executeDispatchesInOrder (EventPluginUtils.js?5d8c:106) at executeDispatchesAndRelease (EventPluginHub.js?0f32:41) at executeDispatchesAndReleaseTopLevel (EventPluginHub.js?0f32:52) at Array.forEach () at forEachAccumulated (forEachAccumulated.js?e2c3:22) resetTranscript @ SpeechRecognition.js?fb07:161 (anonymous) @ makeAssimilatePrototype.js?c7d8:15 boundFunc @ ReactErrorUtils.js?dc41:63 ReactErrorUtils.invokeGuardedCallback @ ReactErrorUtils.js?dc41:69 executeDispatch @ EventPluginUtils.js?5d8c:83 executeDispatchesInOrder @ EventPluginUtils.js?5d8c:106 executeDispatchesAndRelease @ EventPluginHub.js?0f32:41 executeDispatchesAndReleaseTopLevel @ EventPluginHub.js?0f32:52 forEachAccumulated @ forEachAccumulated.js?e2c3:22 processEventQueue @ EventPluginHub.js?0f32:252 runEventQueueInBatch @ ReactEventEmitterMixin.js?91f8:15 handleTopLevel @ ReactEventEmitterMixin.js?91f8:25 handleTopLevelImpl @ ReactEventListener.js?944f:70 perform @ Transaction.js?f15f:141 batchedUpdates @ ReactDefaultBatchingStrategy.js?e9be:60 batchedUpdates @ ReactUpdates.js?8e6b:95 dispatchEvent @ ReactEventListener.js?944f:145

JamesBrill commented 6 years ago

I'm still unable to reproduce this. I can see that there's a context binding problem within the SpeechRecognition component, but can't fathom what's causing it.

Are you able to share the list of devDependencies in your package.json file? This will help me reproduce your build setup.

Don't worry, I'm not going to give up just yet! :)

lorantgulyas commented 6 years ago

Hi, I'm working on this project with @kejtizuki , I also looked into the error, it was quite mysterious. I spent some time with debugging with no success, then I created a new project with one component only. Same code in our part, same import from your npm package and there was no error. Then I started looking at version differences between my two projects and your package, just checked the main parts (react 15.4.0 at our project, 15.4.1 in yours, webpack 1.13.2 in our project, 1.14.0 at yours, babel-core 6.17.0 at ours, 6.21.0 at yours). After these steps I checked your src code, and I though what would happen if I'll just create a separate js file in our project containing your code. I changed the @autobind-s because we are using ES6 and now everything works fine. However I still don't know what went wrong with the npm-package-import method. So the problem we had can be considered as solved, thanks for all the help :)

lorantgulyas commented 6 years ago

Hi again, Just after I send the previous comment I remembered something... I checked my last theory, created a very similar project to ours, same boilerplate and after importing your package and using it in a simple component the error appeared again. I think it is connected to webpack dev server. Below I included the boilerplate we started with, I used this and a simple google speech component in the App.jsx when reproducing the error.

https://github.com/takanabe/react-redux-material_ui-boilerplate

Hope it helps in the debugging process.

JamesBrill commented 6 years ago

Thank you for providing this information and being so patient!

The reason I asked for your devDependencies is because of a bug between the autobind decorator I use from core-decorators and react-hot-loader - issues similar to the ones you experienced occur when old versions of react-hot-loader are used. The issue is discussed here.

The boilerplate you shared includes that older version of the hot loader, so I would wager that that's the cause. Try upgrading react-hot-loader to 2.0.0-alpha-4 or later.

On my side, I should really stop depending on core-decorators and autobind - when I have some time, I'll replace it with some old-school binds.

lorantgulyas commented 6 years ago

Thank you. I updated react-hot-loader and there is no error anymore 🙂