简体   繁体   中英

Using a function as a value to change the state in ReactJS

I am trying to add functionality to the buttons on my app's list so that when UP is clicked the list item swaps with the item directly on top of it.

I tried using a function as a value of my state in setState . But when I click the button this error occurred :

TypeError: Cannot read property 'map' of undefined
App.render
src/App.js:49
  46 | return( 
  47 |   <div>
  48 |     <h1>UNUM Challenge</h1>
> 49 |     <ol>
     | ^  50 |       {this.state.shoppingList.map((item, index) =>
  51 |          (<li data-index = {index} key={index}>
  52 |             {item}

What is happening here? Can't I use a function as the value when setting my state like this?

this.setState({
        shoppingList: arraymove(shoppingList, currentIndex , currentIndex - 1) 
}) 

Here is the full code:

import React, { Component } from 'react';    

function arraymove(arr, fromIndex, toIndex) {
        var element = arr[fromIndex];
        arr.splice(fromIndex, 1);
        arr.splice(toIndex, 0, element);
    }

    class App extends React.Component {
        constructor(props){
        super(props);

        this._handleItemSort = this._handleItemSort.bind(this);

        this.state = {
            shoppingList: ['Bananas', 'Apples', 'Rice', 'Eggs' , 'GTX 1080Ti', 'Avocado']
        }
      }



      _handleItemSort(dir, currentIndex) {
        // create new list of items from a spread of our current shoppingList state.
        // we don't want to reference the actual state and mutate it! 😱
        const shoppingList = [...this.state.shoppingList]

        if (dir === "up" ){
          this.setState({
            shoppingList: arraymove(shoppingList, currentIndex , currentIndex - 1) 
          }) 
        }

      }

      render() {
        return( 
          <div>
            <h1>UNUM Challenge</h1>
            <ol>
              {this.state.shoppingList.map((item, index) =>
                    (<li data-index = {index} key={index}>
                    {item}
                    <div className='controls'>
                      <button 
                        disabled={index === 0} 
                        onClick={ () => this._handleItemSort("up", index) }>UP</button>
                      <button
                        disabled={this.state.shoppingList.length === index + 1}
                        onClick={ () => this._handleItemSort("down", index) } >DOWN</button>
                    </div>
                  </li>)
                )}
            </ol>
          </div>
        );
      }
    }

Returning arr.splice() will give you an array containing the deleted elements. If only one element is removed, an array of one element is returned. If no elements are removed, an empty array is returned.

You need to return modified array like this:

function arraymove(arr, fromIndex, toIndex) {
  var element = arr[fromIndex];
  arr.splice(fromIndex, 1);
  arr.splice(toIndex, 0, element);
  return arr;
}

arraymove doesn't returns, it mutates the state of the list, and return undefined .

So the call

shoppingList: arraymove(shoppingList, currentIndex , currentIndex - 1) 

is equivalent to

shoppingList: undefined

So the fix is minimal:

const shoppingList = [...this.state.shoppingList];
arraymove(shoppingList , currentIndex , currentIndex - 1) 
this.setState({
    shoppingList: shoppingList 
}) 

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