1

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.

1
  • 1
    Why you do so much on render? State modification on render isn't good, also, you modify state directly by using splice, state is supposed to be inmutable. Use slice or filter. Commented Jan 29, 2019 at 18:32

1 Answer 1

2

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

2 Comments

Thanks, this gave me an idea of how I should be doing this
You're welcome, @NoobNewb. If you have any trouble, please let me know.

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.