Failed to execute 'removeChild' on 'Node' with FontAwesome in React

David picture David · Jan 20, 2018 · Viewed 8.6k times · Source

I'm getting the following error whenever I try to use a FontAwesome spinner icon (with className='fa-spin') in React:

Uncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
at removeChild (http://localhost:5000/public/bundle.js:19553:22)
at unmountHostComponents (http://localhost:5000/public/bundle.js:13683:11)
at commitDeletion (http://localhost:5000/public/bundle.js:13727:5)
at commitAllHostEffects (http://localhost:5000/public/bundle.js:14419:13)
at HTMLUnknownElement.callCallback (http://localhost:5000/public/bundle.js:5035:14)
at Object.invokeGuardedCallbackDev (http://localhost:5000/public/bundle.js:5074:16)
at invokeGuardedCallback (http://localhost:5000/public/bundle.js:4931:27)
at commitRoot (http://localhost:5000/public/bundle.js:14508:9)
at performWorkOnRoot (http://localhost:5000/public/bundle.js:15510:42)
at performWork (http://localhost:5000/public/bundle.js:15460:7)

EDIT: The issue has come up a couple of times now, and there's really nothing special about the code itself. I've been using the spinner as a loading icon, and the error occurs whenever the spinner is replaced with content. Example:

return (
  <div>
    {this.state.loading === true ? <i className="fa-spin fas fa-sync"></i> : (
      this.state.recipes.length === 0 ? (
        <div className='text-center'>
          <h2>There doesn't seem to be anything here...</h2><br />
          <h2 style={buttonStyle}>Get started by </h2><button style={buttonStyle} className='btn btn-md btn-success' onClick={(e) => this.props.setView(e, 'browserecipes')}>browsing existing recipes</button><h2 style={buttonStyle}> or </h2><button style={buttonStyle} className='btn btn-success btn-md' onClick={(e) => this.props.setView(e, 'addrecipe')}>adding a recipe.</button>
        </div>
      ) : (
      <div>
          <h1 className='text-center title'>My Recipe Cloud</h1>
          <RecipeContainer
            recipes={this.state.recipes}
            user={this.state.user}
            tags={this.props.tags}
            setView={this.props.setView}
            changeUser={this.changeUser}
          />
        </div>
      )
    )}
  </div>

)

Answer

Sir Neuman picture Sir Neuman · Jan 31, 2018

I think i figured out why this is happening. It appears it has to do with the way FontAwesome 5 replaces <i> tags with <svg> tags. I believe this is incompatible with the way React handles removing elements from the DOM. see: https://fontawesome.com/how-to-use/svg-with-js#with-jquery

The workaround I use is noted at the bottom of that documentation which is to include:

<script>
  FontAwesomeConfig = { autoReplaceSvg: 'nest' }
</script>

I include it in my header, which there might be a better placement for it, but it appears to resolve the issue for me at least. It might affect some CSS logic you could have for any classes which you have directed specifically at FontAwesome elements that are direct children of other classes/ids so you might want to just check to make sure all of your styling looks right, since it's now nesting the <svg> tag within the <i> tag instead of replacing it.

Alternatively you could just wrap the <i> tag yourself. For example:

{this.state.loading === true ? <div><i className="fa-spin fas fa-sync"></i></div> ...

should work.

UPDATE (12/10/18): Now there is a better explanation in the documentation for why this is happening in the official docs and an explanation for how to integrate this FontAwesome with a javascript library here. The method for automatically nesting your <i> tags is now done inside the script tag for fetching the FontAwesome javascript library <script src="https://use.fontawesome.com/releases/v5.5.0/js/all.js" data-auto-replace-svg="nest"></script>. There is also now official support for the FontAwesome React library which resolves this issue as well.