Casandra
Casandra

Reputation: 160

Map function loops and gives error - React

I have created tabs that are created by clicking on a menu item. After that I wanted the closing "X" to only appear when hovering over the <li> parent.

I think it's a map problem that has not yet been created when I try to paint the "X" hover, but I do not know how to fix it. Why do I get this error? Can not update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state.

class LiTabs extends Component{
    constructor(props, context){
        super(props, context);

        ["showCloseTabs",].forEach((method) => {
            this[method] = this[method].bind(this);
        });

        this.state = {
            closeTabs: false,
        };
    }

    showCloseTabs(e){
        this.setState({
            closeTabs : true, 
        })
        console.log(e);
    }

    render(){
        return(
            <>
            {this.props.tabsLi.map((value, index) =>
                <li key={index} onMouseOver={this.showCloseTabs(this)}>
                    <span>{value}</span>
                    <div onClick={this.props.removeTab.bind(this, value, index)} >
                        {this.state.closeTabs === true && (
                            <Icon icon="cerrar" className='ico-cerrar'/>
                        )}
                    </div>
                </li>
            )}         
            </>
        );
    }
}

Upvotes: 1

Views: 94

Answers (2)

Icepickle
Icepickle

Reputation: 12806

You are missing a bind on this.showCloseTabs(this) which causes it to call it directly

To be fair, you should probably just remove the (this) all together there though (so even not have the bind in the mapping function)

{this.props.tabsLi.map((value, index) =>
    <li key={index} onMouseOver={this.showCloseTabs.bind(this)}>
        <span>{value}</span>
        <div onClick={this.props.removeTab.bind(this, value, index)} >
            {this.state.closeTabs === true && (
                <Icon icon="cerrar" className='ico-cerrar'/>
            )}
        </div>
    </li>
)}         

To use class properties, you can change the declaration of your method like

showCloseTabs = (e) => { /* ... */ }

In both cases, you could then change the onMouseOver property to be

onMouseOver={this.showCloseTabs}

And be done with it :)

Upvotes: 2

Agney
Agney

Reputation: 19224

this.showCloseTabs(this) is a function call in JavaScript, this means that function is called when render method is called.

This function is doing a setState which leads to the error:

Can not update during an existing state transition (such as within render). Render methods should be a pure function of props and state.

What needs to be passed to onMouseOver or onClick are references to the functions. In case of showCloseTabs, that is going to be:

onMouseOver={this.showCloseTabs}

If you need to pass arguments:

onMouseOver={(e) => this.showCloseTabs(e)}

Also binding the method in render creates new functions very time render is called. Instead you can bind it in the constructor:

constructor() {
  this.onMouseOver = this.onMouseOver.bind(this);
}

Upvotes: 2

Related Questions