最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React 16: Error: Unable to find node on an unmounted component - Stack Overflow

programmeradmin3浏览0评论

I recently upgraded my project from React v15.2.1 to 16.4.1 and my Sidebar component is throwing the following error:

Error: Unable to find node on an unmounted component. bundle.js line 1326 > eval:42:15
invariant
webpack:///./node_modules/fbjs/lib/invariant.js?:42:15
findCurrentFiberUsingSlowPath
webpack:///./node_modules/react-dom/cjs/react-dom.development.js?:3817:7
findCurrentHostFiber
webpack:///./node_modules/react-dom/cjs/react-dom.development.js?:3886:23
findHostInstance
webpack:///./node_modules/react-dom/cjs/react-dom.development.js?:16824:19
findDOMNode
webpack:///./node_modules/react-dom/cjs/react-dom.development.js?:17310:12
handleClickOutside
webpack:///./src/components/simulator/sidebar/Sidebar.js?:99:31
handleClickOutside self-hosted:984:17

Based on the error message, I believe the error is happening when calling ReactDOM.findDOMNode(this) in the handleClickOutside(event) method.

The component that I am using can be found here: /, I have changed it a little bit to this:

import React from 'react'
import ReactDOM from 'react-dom'
import classNames from 'classnames'
import SimulatorForm from './SimulatorForm'
import './Sidebar.scss'

const  openForm = require('../../../public/icons/si-glyph-arrow-left.svg');
const closeForm = require('../../../public/icons/si-glyph-arrow-right.svg');
const   pinForm = require('../../../public/icons/si-glyph-pin-location-love.svg');
const unpinForm = require('../../../public/icons/si-glyph-pin-location-delete.svg');

class Sidebar extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            showMenu: false,
            isMenuPinned: false,
            formIcon: openForm,
            pinIcon: pinForm,
            modelsDescription: props.modelsDescription
        }
        // Methods to pin/unpin the Form
        this.toggleMenu = this.toggleMenu.bind(this)
        this.pinMenu = this.pinMenu.bind(this)
        // Handlers
        this.handleSelectedModelChange = this.props.handleSelectedModelChange
        this.handleNewMasterGraphsData = this.props.handleNewMasterGraphsData
        this.handleNewResults = this.props.handleNewResults
    }
    componentWillReceiveProps(nextProps) {
        this.setState({ modelsDescription: nextProps.modelsDescription});
    }
    componentDidMount() {
        document.addEventListener('click', this.handleClickOutside.bind(this), true);
    }

    componentWillUnmount() {
        document.removeEventListener('click', this.handleClickOutside.bind(this), true);
    }
    pinMenu() {
        this.setState({
            isMenuPinned: !this.state.isMenuPinned,
            pinIcon: this.state.isMenuPinned ? pinForm : unpinForm
        });
    }
    toggleMenu() {
        this.setState({
            showMenu: !this.state.showMenu,
            formIcon: this.state.showMenu ? openForm : closeForm
        });
    }
    handleClickOutside(event) {
        if (!this.state.isMenuPinned) {
            const domNode = ReactDOM.findDOMNode(this);

            if ((!domNode || !domNode.contains(event.target))) {
                this.setState({
                    showMenu: false,
                    formIcon: openForm
                });
            }
        }
    }

    render() {
        const showMenu = this.state.showMenu;
        const sidebarClass = classNames({
            'sidebar': true,
            'sidebar-menu-expanded': showMenu,
            'sidebar-menu-collapsed': !showMenu
        });

        const elementsClass = classNames({
            'expanded-element': true,
            'is-hidden': !showMenu,
        });

        return (
            <nav className={sidebarClass}>
                <img className="menuIcon" src={this.state.formIcon} height="42" width="42" onClick={this.toggleMenu} />
                <ul>
                    <li>
                        {
                            this.state.showMenu ? <img className="pinIcon" src={this.state.pinIcon}  height="42" width="42" onClick={this.pinMenu} /> : null
                        }
                    </li>
                    <li>
                        {
                            this.state.showMenu ?  <SimulatorForm modelsDescription={this.state.modelsDescription} handleSelectedModelChange={this.handleSelectedModelChange}
                                                    handleNewMasterGraphsData={this.handleNewMasterGraphsData} handleNewResults={this.handleNewResults} /> : null
                        }        
                    </li>
                </ul>
            </nav>
        )
    }
}


export default Sidebar

Lastly, the error is only thrown when I reload the page. If I don't, it seems to be working perfectly fine. Do you have any suggestions or recommendations to make sure the error is not thrown again?

I have been reading about this on-line and I couldn't find a fix for it. Also, I dont't think this is listed as a breaking change but I could be very wrong.

I recently upgraded my project from React v15.2.1 to 16.4.1 and my Sidebar component is throwing the following error:

Error: Unable to find node on an unmounted component. bundle.js line 1326 > eval:42:15
invariant
webpack:///./node_modules/fbjs/lib/invariant.js?:42:15
findCurrentFiberUsingSlowPath
webpack:///./node_modules/react-dom/cjs/react-dom.development.js?:3817:7
findCurrentHostFiber
webpack:///./node_modules/react-dom/cjs/react-dom.development.js?:3886:23
findHostInstance
webpack:///./node_modules/react-dom/cjs/react-dom.development.js?:16824:19
findDOMNode
webpack:///./node_modules/react-dom/cjs/react-dom.development.js?:17310:12
handleClickOutside
webpack:///./src/components/simulator/sidebar/Sidebar.js?:99:31
handleClickOutside self-hosted:984:17

Based on the error message, I believe the error is happening when calling ReactDOM.findDOMNode(this) in the handleClickOutside(event) method.

The component that I am using can be found here: https://ashiknesin.com/blog/build-custom-sidebar-component-react/, I have changed it a little bit to this:

import React from 'react'
import ReactDOM from 'react-dom'
import classNames from 'classnames'
import SimulatorForm from './SimulatorForm'
import './Sidebar.scss'

const  openForm = require('../../../public/icons/si-glyph-arrow-left.svg');
const closeForm = require('../../../public/icons/si-glyph-arrow-right.svg');
const   pinForm = require('../../../public/icons/si-glyph-pin-location-love.svg');
const unpinForm = require('../../../public/icons/si-glyph-pin-location-delete.svg');

class Sidebar extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            showMenu: false,
            isMenuPinned: false,
            formIcon: openForm,
            pinIcon: pinForm,
            modelsDescription: props.modelsDescription
        }
        // Methods to pin/unpin the Form
        this.toggleMenu = this.toggleMenu.bind(this)
        this.pinMenu = this.pinMenu.bind(this)
        // Handlers
        this.handleSelectedModelChange = this.props.handleSelectedModelChange
        this.handleNewMasterGraphsData = this.props.handleNewMasterGraphsData
        this.handleNewResults = this.props.handleNewResults
    }
    componentWillReceiveProps(nextProps) {
        this.setState({ modelsDescription: nextProps.modelsDescription});
    }
    componentDidMount() {
        document.addEventListener('click', this.handleClickOutside.bind(this), true);
    }

    componentWillUnmount() {
        document.removeEventListener('click', this.handleClickOutside.bind(this), true);
    }
    pinMenu() {
        this.setState({
            isMenuPinned: !this.state.isMenuPinned,
            pinIcon: this.state.isMenuPinned ? pinForm : unpinForm
        });
    }
    toggleMenu() {
        this.setState({
            showMenu: !this.state.showMenu,
            formIcon: this.state.showMenu ? openForm : closeForm
        });
    }
    handleClickOutside(event) {
        if (!this.state.isMenuPinned) {
            const domNode = ReactDOM.findDOMNode(this);

            if ((!domNode || !domNode.contains(event.target))) {
                this.setState({
                    showMenu: false,
                    formIcon: openForm
                });
            }
        }
    }

    render() {
        const showMenu = this.state.showMenu;
        const sidebarClass = classNames({
            'sidebar': true,
            'sidebar-menu-expanded': showMenu,
            'sidebar-menu-collapsed': !showMenu
        });

        const elementsClass = classNames({
            'expanded-element': true,
            'is-hidden': !showMenu,
        });

        return (
            <nav className={sidebarClass}>
                <img className="menuIcon" src={this.state.formIcon} height="42" width="42" onClick={this.toggleMenu} />
                <ul>
                    <li>
                        {
                            this.state.showMenu ? <img className="pinIcon" src={this.state.pinIcon}  height="42" width="42" onClick={this.pinMenu} /> : null
                        }
                    </li>
                    <li>
                        {
                            this.state.showMenu ?  <SimulatorForm modelsDescription={this.state.modelsDescription} handleSelectedModelChange={this.handleSelectedModelChange}
                                                    handleNewMasterGraphsData={this.handleNewMasterGraphsData} handleNewResults={this.handleNewResults} /> : null
                        }        
                    </li>
                </ul>
            </nav>
        )
    }
}


export default Sidebar

Lastly, the error is only thrown when I reload the page. If I don't, it seems to be working perfectly fine. Do you have any suggestions or recommendations to make sure the error is not thrown again?

I have been reading about this on-line and I couldn't find a fix for it. Also, I dont't think this is listed as a breaking change but I could be very wrong.

Share Improve this question asked Jul 16, 2018 at 15:31 Alessandro CaliAlessandro Cali 4191 gold badge6 silver badges13 bronze badges 2
  • Binding a function creates a new function object, and even though the one you pass when you add a handler and the one you pass when you want to remove that handler seem to be the same, they're not considered equal, so you end up not removing that handler. Storing a bound function in a property by setting it in the constructor is one of the ways to resolve your issue. – user6019272 Commented Jul 18, 2018 at 21:43
  • Hello, I have the same problem as you and I am wondering why this problem is incidental? As in your example, this problem is only triggered when you reload the page. Why? Looking forward to hearing from you soon. Thanks. – DangoSky Commented Nov 26, 2020 at 7:23
Add a comment  | 

3 Answers 3

Reset to default 9

I ended up finding the solution thanks to the help of the original writer of the code. Link can be found here. It was a problem with my bindings, more details on the link.

I have changed:

componentDidMount() {
   document.addEventListener('click', this.handleClickOutside.bind(this), true);
}

componentWillUnmount() {
   document.removeEventListener('click', this.handleClickOutside.bind(this), true);
}

to

componentDidMount = () => {
   document.addEventListener("click", this.handleClickOutside, true);
};

componentWillUnmount = () => {
   document.removeEventListener("click", this.handleClickOutside, true);
};

I just use material ui Menu from another package and got same issue , it strange but installing latest (similar to the spa version) react-dom solve the issue.

Maybe your dependence have an issues. So please remove your node_modules folder, and run this code to install dependence again:

npm i --legacy-peer-deps
发布评论

评论列表(0)

  1. 暂无评论