2

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>
        );
      }
    }
3
  • arraymove doesn't return anything add a return to the end of your function arraymove with return arr Commented Oct 26, 2018 at 14:40
  • Your arraymove function doesn't return anything - so this.setState({shoppingList: arraymove(shoppingList, currentIndex , currentIndex - 1) }) is equivalent to this.setState({shoppingList: undefined}). Which I'm sure is not what you want. Commented Oct 26, 2018 at 14:40
  • Thank you for your comment, I tried adding return like this: return arr.splice(toIndex, 0, element); but the error is still there Commented Oct 26, 2018 at 14:43

2 Answers 2

2

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;
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! So stupid of me of not using a modified array. I will mark your answer in 5 minutes
1

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 
}) 

2 Comments

Thank you for pointing it out. So I tried this: ` function arraymove(arr, fromIndex, toIndex) { var element = arr[fromIndex]; arr.splice(fromIndex, 1); return arr.splice(toIndex, 0, element); } ` and the error is the same
You can keep mutates the array in place, just try the updated example!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.