简体   繁体   中英

Setting state in OnMouseOver event returns TypeError: Cannot read property - React

Although finding loads of posts about this error, I can't seem to fix it in my specific case.

I have a set of items and I am trying to color these items (the div's) when you hover over them. The coloring happens when the state of these items ( reserved ) is false and the starting state is set to true. So when an item is clicked ( MouseDown event) I am setting the starting condition (state to true), then when I mouse over the next item, and the start condition is true and the item being moused over has it's reserved state property set to false, it should change it's background color and so on for the next items which are being moused over.

This is now being done as follows:

Defining the Items and start condition in the (initial) state:

constructor(props) {
    super(props);

    this.state = {
        items: [
            {
                name: 'test1',
                key: '#test1',
                reserved: false,
            },
            {
                name: 'test2',
                key: '#test2',     
                reserved: false, 
            },
            {
                name: 'test3',
                key: '#test3',
                reserved: false,  
            },
            {
                name: 'test4',
                key: '#test4',
                reserved: false,  
            },
            {
                name: 'test5',
                key: '#test5',
                reserved: false,   
            },
        ],

        startCondition: false

    }
}

Render the List item:

render() {

  return (    
    <FocusZone>
      <List
        items={this.state.items}
        onRenderCell={this._onRenderCell}
      />
    </FocusZone>
  );
}

In the _onRenderCell event I am rendering each cell (item div) and setting the onMouseDown , onMouseUp and onMouseOver events, I also check the reserved state of the item here so that when the item becomes reserved = true it gets an extra css class which contains the different background color:

_onRenderCell = (item, index) => {

    let className = 'ms-ListGridExample-label';

    if (item.reserved === true) {
        className += ' reservation-creating';
    }

    return (
      <div
        className="ms-ListGridExample-tile"
        data-is-focusable={false}
        style={{
          width: 100 / this._columnCount + '%',
          height: this._rowHeight * 1.5,
          float: 'left'
        }}
      >
        <div className="ms-ListGridExample-sizer">
          <div className="msListGridExample-padder">

            <span className={className}
                 onMouseOver={() => this._onMouseOver(item.name)} 
                 onMouseUp={() => this._onMouseUp(item)} 
                 onMouseDown={() => this._onMouseDown(item.name)} 
            >
                {item.name}

            </span>

            <span className="urenboeken-bottom"></span>
          </div>
        </div>
      </div>
    );
};

So when an item is clicked ( MouseDown event) it sets the starting condition to true and also set it to reserved to give it the extra css class (with it's different background color ):

_onMouseDown(name){
    if (this.state.startCondition === false){
        this.setState({startCondition: true});

        this.setState(prevState => ({
            items: prevState.items.map(item => {

                if (item.name === name) {
                    if (item.reserved === true)
                    {
                        item.reserved = false
                    }
                    else if (item.reserved === false)
                    {
                        item.reserved = true
                    }
                    else
                    {
                        item.reserved = false
                    }
                }
                return item;
            })
        }))
    }
}

After the MouseDown event has been fired and the Start Condition is being set, the moving will be tracked with the MouseOver event and setting the reserved state to true:

 _onMouseOver(name) {
    if (this.state.startCondition === true) {

        this.setState(prevState => ({
            items: prevState.items.map(item => {
                if (item.reserved === false) {
                    if (item.name === name) {
                        item.reserved = true
                    }

                    return item;
                }
            })
        })) 
    }
}

At this point, the _OnRenderCell is fired again and returns me the error:

MyClass.js:265 Uncaught TypeError: Cannot read property 'reserved' of undefined
    at MyClass._this._onRenderCell

which is the following part in the _onRenderCell function:

if (item.reserved === true) 

I am probably doing something obvious wrong but I cant seem to point out what it is.

Ps the onMouseUp event reset the starting condition to false.

UPDATE

On request of @M.Fazio, who suspects something is going wrong with the items={this.state.items} part in the List rendering, I added a log to display what is inside the items just before rendering:

render() {
    let tItems; 

    tItems = this.state.items.map(item => { 
        console.log('Item name = ' + item.name + ' item reserved = ' + item.reserved);
    });  

  return (  

    <FocusZone>
      <List
        items={this.state.items}
        onRenderCell={this._onRenderCell}
      />
    </FocusZone>
  );
}

Result:

在此处输入图片说明

Some things to point out:

  • The OnRenderCell gets called for every item in the array (which is logical).
  • The List rendering seem to happen three times, why?
  • When doing the process ( onMouseDown + onMouseOver event) the following happens (error now actually already happens on the added logging): 在此处输入图片说明

Solution

@M.Fazio found the solution. In the end it was a small glitch (though so hard to find for myself). The return item; in the _onMouseOver event was inside the if condition , moving it outside the if condition made it working!

In your ListComponent , when you're calling the onRenderCell prop, you have to pass your parameters. Did you ? Maybe past the code of your ListComponent so we can help you ?

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