1

I was practicing todo list in React and I faced a problem that I don't understand. Can't delete the item from the array that is in my state. I'm passing the index to my delete function and than I was trying to filter through the array to set a new State.

Here is the code of my App component:

class App extends React.Component {
  state = {
    tasks : []
  }

  addToScreen = (task) => {
    const tasks = { ...this.state.tasks } 
    tasks[`task${Date.now()}`] = task
    this.setState(prevState => ({
      tasks: [...prevState.tasks, task]
    }))
  }


  deleteTask = index => {
    const reducedArr = this.state.tasks.filter( (item) => {
      return item[index] !== item 
    })
    this.setState({
      tasks: reducedArr
    })
  }


  render() {
    return (
      <>
        <Input addToScreen={this.addToScreen}/>
        <Screen tasks={this.state.tasks} deleteTask={this.deleteTask}/>
      </>
    );
  }
}

And here is my Screen component:

class Screen extends React.Component {
  render() {
    return ( 
      <ul>
        {this.props.tasks.map((key, index) => <li key={index}>{key}
        <button onClick={() => this.props.deleteTask(index)}>x</button>
        </li>)}  
      </ul>
    )
  }
}

So it when you press the button on my screen component it should remove the specific value from the state. Thanks for help or any tips!

jakmas
  • 83
  • 1
  • 1
  • 8
  • You can use the `splice()` method instead of filter https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice – Valentin Duboscq May 03 '19 at 15:35
  • Possible duplicate of [What is the cleanest way to remove an element from an immutable array in JS?](https://stackoverflow.com/questions/47023975/what-is-the-cleanest-way-to-remove-an-element-from-an-immutable-array-in-js) – Emile Bergeron May 03 '19 at 15:54

4 Answers4

4

Instead of item[Index], it should be the index of item in filter callback function.

Like this:

deleteTask = index => {
  const reducedArr = this.state.tasks.filter((item, itemIndex) => {
    return itemIndex !== index 
  })

  this.setState({
    tasks: reducedArr
  })
}

Also use updater function with setState (because you are updating an array and setState is async in nature, check the react doc for more details), write the same function as:

deleteTask = index => {
  this.setState(prevState => ({
    tasks: prevState.tasks.filter((item, itemIndex) => itemIndex != index)
  }))
}
Mayank Shukla
  • 100,735
  • 18
  • 158
  • 142
3

I'm also new to React! I've just been working on something similar:

deleteTask = (index) => {

    const reducedArr = [...this.state.tasks];

    reducedArr.splice(index, 1);

    this.setState({tasks: reducedArr})

  }

EDIT: credit here goes to Maximilian Schwarzmüller of Academind. I'm doing the React Complete Guide

JakePowell
  • 90
  • 6
  • Thanks a lot! I've tried with ```reducedArr.splice``` but I messed it up a little. – jakmas May 03 '19 at 15:40
  • 1
    Be careful, because `Array.prototype.splice` performs a mutation and According to [React Docs](https://reactjs.org/docs/react-component.html#state): _state_ is a reference to the component state at the time the change is being applied. It should not be directly mutated. Instead, changes should be represented by building a new object based on the input from _state_ and _props_. – arkeros May 03 '19 at 16:11
  • In this case is this not ok as it's mutating reducedArr and then merging the two? – JakePowell May 03 '19 at 16:46
0

The right way is to use splice. It removes items from an array and, optionally, replaces them with new ones. This is the syntax:

  array.splice(start[, deleteCount[, item1[, item2[, ...]]]]);

Your function could read:

  deleteTask (index) { // Just so you don't need to bind `this`
    this.state.tasks.splice(index, 1);
    this.setState({
      tasks: this.state.tasks
    })
  }

Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice

JP de la Torre
  • 1,593
  • 18
  • 20
0

You need to bind this to your handler

  render() {
    return (
      <>
        <Screen
          tasks={this.state.tasks}
          deleteTask={this.deleteTask.bind(this)}
        />
      </>
    );
  }

Also, your filter is buggy, is filtering out by value, not by index. I fixed it:

    const reducedArr = this.state.tasks.filter((_, key) => {
      return key !== index;
    });

You have a demo on CodeSandbox

arkeros
  • 177
  • 3