NoobNewb
NoobNewb

Reputation: 653

Deleting component elements from an array in reactjs

I'm fairly new to react. What I'm trying to do is to delete a component from an array given an index when the "[x]" button is clicked. From what I understood react re-renders the Component whenever the state has changed.

The labels variable on the render() method is an array of components and also has other child components. When the user clicks the [x] on one of the components, it would pass the index of that to the class function closeLabelHandler() and assign the state objects, indexToDelete and isDeletingLabel to the index of the element and true, respectively.

Since I am changing a state object, I was thinking that this during the re-render an element would be deleted from the labels array but alas, it doesn't.

Here's my code:

import React, { Component } from 'react';
import "./ImageContainer.css";
import { Stage, Layer, Image, Tag, Text, Label } from 'react-konva';
import ToolsContainer from '../ToolsContainer/ToolsContainer';

class ImageContainer extends Component {
    state = {
        showImageContainer: true,
        canvasHeight: 0,
        canvasWidth: 0,
        canvasImageUrl: "",
        image: null,
        commentsArray: [],
        labelCount: 0,
        isDeletingLabel: false,
        indexToDelete: -1
    }


    componentDidMount() {
        let stage = this.refs.stage
        const imgObj = new window.Image();
        imgObj.src = this.props.selectedImageURI

        imgObj.onload = () => {
            this.setState({ image: imgObj })
            this.setState({ canvasWidth: imgObj.width, canvasHeight: imgObj.height });
            let canvasImageUrl = stage.toDataURL();
            this.setState({ canvasImageUrl: canvasImageUrl })
        }


    }

    getLabelCount = (count) => {
        this.setState({ labelCount: count })
    }

    displayContainerHandler = () => {
        this.props.showImageContainer(!this.state.showImageContainer)
    }

    downloadImageHandler = () => {
        let a = document.createElement('a');
        a.href = this.state.canvasImageUrl.replace("image/png", "image/octet-stream");
        a.download = 'shot.png';
        a.click();
    }

    closeLabelHandler = (index) => {
        this.setState({
            isDeletingLabel: true,
            indexToDelete: index
        })
        console.log("[closeLabelHandler] " + index)
    }



    render() {

        console.log("[ImageContainer][render]" + this.state.commentsArray)
        let labels = [];

        for (let i = 0; i < this.state.labelCount; i++) {
            labels.push(
                <Label key={i} draggable={true} x={150 + i * 2} y={150 + i * 2} >
                    <Tag
                        fill="black"
                        pointerWidth={10}
                        pointerHeight={10}
                        lineJoin='round'
                        shadowColor='black'
                    />
                    <Text
                        text="Insert Comment Here"
                        fontFamily='Calibri'
                        fontSize={18}
                        padding={5}
                        fill='white'
                    />
                    <Text
                        text="[x]"
                        fontFamily='Calibri'
                        fontSize={18}
                        x={170}
                        fill='black'
                        onClick={() => this.closeLabelHandler(i)}
                    />
                </Label>
            )
            if (this.state.isDeletingLabel) {
                labels.splice(this.state.indexToDelete, 1)
                this.setState({
                    isDeletingLabel: false,
                    indexToDelete: -1
                })
            }

        }

        return (
            <div className="ImageContainer" >
                <button className="ImageContainer-close-button " onClick={this.displayContainerHandler}>[x]</button>
                <Stage ref="stage" height={this.state.canvasHeight * .5} width={this.state.canvasWidth * .5} >
                    <Layer>
                        <Image image={this.state.image} scaleX={0.5} scaleY={0.5} />
                        {labels}
                    </Layer>
                </Stage>
                <ToolsContainer getLabelCount={count => this.getLabelCount(count)} />
                <button className="pure-button" onClick={() => this.downloadImageHandler()}>Download</button>
            </div>
        )
    }
}

Any help would be appreciated.

Upvotes: 1

Views: 82

Answers (1)

Cris Soares
Cris Soares

Reputation: 627

This is a simple way to achive what you want. You should not change your state directly, it could cause inconsistency to your application.

import React, { Component } from "react";
class Books extends Component {
   state = {
      books: [{ id: 1, title: "Book 1" }, { id: 2, title: "Book 2" }]
   };
   handleDelete = book => {
      const books = this.state.books.filter(b => b.id !== book.id);
      this.setState({ books });
   };
   render() {
      return (
         <ul>
            {this.state.books.map(book => (
               <li key={book.id}>
                  {book.title}{" "}
                  <button onClick={() => this.handleDelete(book)}>x</button>
               </li>
            ))}
         </ul>
      );
   }
}

export default Books;

Upvotes: 2

Related Questions