GosuGod
GosuGod

Reputation: 300

React splice child component trouble

I have (for example) 2 components. Of course, 1 of them is Parent, and another one is a Child of Parent. My goal is to delete component by button, but when I press the delete button inside child component, function deleting next component. Maybe I forgot something?

Example: [[1],[2],[3]] - That is nested array with another arrays. I want to remove [2] (parentArray[1]). But delete function removing [3] (parentArray[2]) and i have [[1],[2]]. That is my trouble.

Parent component:

import React from 'react'
import classes from './Kanban.module.scss'
import Card from './Card/Card.js'

export default class Kanban extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      cards: [
      ]
    }

    this.createCardHandler = this.createCardHandler.bind(this);
    this.deleteCardHandler = this.deleteCardHandler.bind(this);
  }

  createCardHandler() {

    this.setState({
      cards: this.state.cards.concat({ id: this.state.cards.length })
    })

  }

  deleteCardHandler(index) {

    this.setState(prevState => {

      let cards = [...prevState.cards]

      cards.splice(index, 1)

      return {
        cards: cards
      }

    })

  }

  render() {
    let cards = null;

    cards = this.state.cards.map((cards, id) => {


      return (
        <Card
          index={cards.id}
          id={cards.id}
          onDelete={this.deleteCardHandler.bind(this, id)}
        />
      )
    })

    return (
      <>
        <div>
          <button className={classes.CreateCardButton} onClick={this.createCardHandler}>+</button>
          {cards}

        </div>
      </>
    )
  }
}

Child component:

import React from 'react'
import classes from './Card.module.scss'
import List from './List/List.js'

export default class Card extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      lists: []
    }

    this.CreateListButton = this.CreateListButton.bind(this);
  }

  CreateListButton() {

    this.setState({
      lists: this.state.lists.concat('List')
    })

  }

  deleteListHandler(index) {
    let lists = [...this.state.lists]

    lists.splice(index, 1)

    this.setState({
      lists
    })
  }

  render() {
    let lists = null

    lists = this.state.lists.map((lists, index) => {
      return (
        <List
          index={this.state.lists.length - 1}
          onDelete={this.deleteListHandler.bind(this, index)}
        />
      )
    })
    return (

      <div className={classes.Card}>

        <button className={classes.DeleteCardButton} onClick={this.props.onDelete}>✖</button>

        <input maxLength='18' autoFocus className={classes.InputTitleInCard}></input>

        {lists}

        <button className={classes.CreateNewListButton} onClick={this.CreateListButton}>CREATE NEW LIST</button>

      </div>

    )
  }


}

Upvotes: 0

Views: 491

Answers (3)

Ajay
Ajay

Reputation: 11

When you set the state use the Spread Operator it worked for me.

this.setState({
    lists
})

changed like this

this.setState({
    [...lists]
})

Upvotes: 1

Aman Kumar
Aman Kumar

Reputation: 399

The issue is with you delete handler. Initially the state of your Kanban class is []. Then, lets say you add 4 cards, it would then become [{id: 0}, {id: 1}, {id: 2}, {id: 3}] So, if you delete say the 2nd card, your new state becomes,

[{id: 0}, {id: 2}, {id: 3}]

Now, if you try to delete the 3rd card, i.e. id=2, your handler deletes the index 2 element from state, i.e. element with id 3. So, the element your click, the next element would get deleted. Don't rely on the array index(this mapping won't work once you delete any card), rely on the id's that you have created for cards. The way you have written delete handler is not proper. Here is a solution, this should fix the issue.

deleteCardHandler(index) {
    this.setState(previousState => previousState.filter(card => card.id !== index))
}

This basically returns an array with all the elements except for the one on which you clicked delete. Hope it helps!!!

Upvotes: 0

Praveen Tamil
Praveen Tamil

Reputation: 1156

Please add an index prop to your child component

cards = this.state.cards.map((card, index) => {
  return (
    <Card
      index={card.id}
      id={card.id}
      //Here i giving child component function from parent component
      onDelete={this.deleteCardHandler.bind(this, index)}
    />
  )
})

Upvotes: 0

Related Questions