Reputation: 737
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>
);
}
}
Upvotes: 2
Views: 1640
Reputation: 17048
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
})
Upvotes: 1
Reputation: 1441
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;
}
Upvotes: 2