简体   繁体   中英

getElementById after conditionally rendering with setState

I have a trigger button that will open a dialog asking if a user would like to enable text to speech. Once the dialog is open, I want to focus on the yes button within the dialog by getting the button element by its ID.

When the trigger is pressed, the following function is called:

  private openTTSDialog = () => {
    if (this.state.ttsDialog === true) {
      this.setState({ ttsDialog: false })
    } else {
      this.setState({ ttsDialog: true }, () => {
        // search document once setState is finished
        const yesButton = document.getElementById('tts-dialog-yes-button')
        log('yesButton', yesButton)
        if (yesButton) {
          yesButton.focus()
        }
      })
    }
  }

And my dialog is conditionally rendered with a ternary expression like this:

{
  this.state.ttsDialog ? (
    <div className="tts-dialog-container">
      <div className="tts-dialog-text-container">
        {session.ttsEnabled ? (
          <div>
            {
              strings.disableTTS
            }
          </div>
        ) : (
          <div>
            {
              strings.enableTTS
            }
          </div>
        )}
      </div>
      <div className="tts-dialog-button-container">
        <button
          aria-label={strings.yes}
          tabIndex={0}
          className="tts-dialog-button"
          id="tts-dialog-yes-button"     // this is the button I want to focus
          onClick={this.toggleTTS}
        >
          {
            strings.yes
          }
        </button>
        <button
          aria-label={strings.no}
          tabIndex={0}
          className="tts-dialog-cancelButton"
          onClick={this.closeTTSDialog}
        >
          {
            strings.no
          }
        </button>
      </div>
    </div>
  ) : null
}

My log for yesButton is undefined. I thought adding the callback function to setState would fix this because I would be searching the document after setState was finished, but I'm still missing something. Any idea what it is?

In the constructor of your class, you should add a ref to your button:
this.myRef = React.createRef();
Then in your button:

<button
          ref={this.myRef}
          aria-label={strings.yes}
          tabIndex={0}
          className="tts-dialog-button"
          id="tts-dialog-yes-button"     // this is the button I want to focus
          onClick={this.toggleTTS}
        >

Finally, instead of doing:

const yesButton = document.getElementById('tts-dialog-yes-button')

You should do:

const yesButton = = this.myRef.current;

Actually I would also think this should work since you use a callback on setState , so the new render should have completed and the element should already be mounted and accessible. Anyway I think the idiomatic React way for this would be to use a ref ( https://reactjs.org/docs/refs-and-the-dom.html ) and put it on the button like <button ref={this.yesButton}...>...</button> and then call this.yesButton.focus() . Have you tried that already?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM