React .map每次更新都会渲染整个数组并导致重复

时间:2019-01-30 17:06:02

标签: reactjs

美好的一天,

我正在尝试将每个对象数组映射到render方法中的<Label>组件。单击“ 添加注释”会将注释对象添加到<ToolsContainer>组件的状态数组中。更新<ToolsContainer>状态数组后,它对<ImageContainer>进行回调,以获取值,然后更新<ImageContainer>自己的状态数组。

更新后,我将<ImageContainer>的状态数组映射到<Label>组件上,该组件可以工作,但是这并不是我希望它表现的方式。问题是,每当我添加另一个“注释”时,它都会渲染数组中的所有内容,即使使用uuid,它也会导致重复。

此处演示:https://codesandbox.io/s/lvm1n7w89

  • 使用方法:
    1. 点击获取屏幕截图
    2. 点击下面的任何屏幕截图
    3. 点击添加注释
    4. 您可以在周围拖动注释

以下代码: ToolsContainer.js

import React, { Component } from 'react';
import Button from '../../components/UI/Button/Button'
import uuid from "uuid";

class ToolsContainer extends Component {
    state = {
        isAddingAnnotation: false,
        commentArray: [],
        comment: "",                                                              
        labelCount: 0
    }
    addCommentHandler = () => {
        let comment = {
            uuid: uuid.v4(),
            value: "Insert comment here"
        }
        this.setState({
            commentArray: [...this.state.commentArray, comment]
        }, () => {
            console.log("[ToolsContainer][addCommentHandler] " + this.state.commentArray)
            this.props.getCommentsHandler(this.state.commentArray)
        })

    }
    render() {
        return (
            <div className="pure-g">
                <Button gridClass={"pure-u-4-24"} buttonName={"Add Annotation"} onClick={() => this.addCommentHandler} />
            </div>

        )
    }
}

export default ToolsContainer;

ImageContainer.js

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: [],

    }

    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();
    }

    onDragEnd(event) {
        console.log(event.target)
    }

    handleDelete = comment => {
        const commentsArray = this.state.commentsArray.filter(c => c.uuid !== comment.uuid);
        this.setState({ commentsArray });
    };

    getCommentsHandler = (comments) => {
        console.log("[ImageContainer][getCommentsHandler] " + comments)
        this.setState({
            commentsArray: [...this.state.commentsArray, ...comments]
        }, () => {
            console.log("[ImageContainer][getCommentsHandler] " + this.state)
        })
    }


    render() {
        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} />
                        {this.state.commentsArray.map(comment => (
                            <Label key={comment.uuid} draggable={true} x={150} y={150}>
                                <Tag
                                    fill="black"
                                    pointerWidth={10}
                                    pointerHeight={10}
                                    lineJoin='round'
                                    shadowColor='black'
                                />

                                <Text
                                    text={comment.value}
                                    fontFamily='Calibri'
                                    fontSize={18}
                                    padding={5}
                                    fill='white'
                                />

                                <Text
                                    text="[x]"
                                    fontFamily='Calibri'
                                    fontSize={18}
                                    x={170}
                                    fill='black'
                                    onClick={() => this.handleDelete(comment)}
                                />
                            </Label>
                        ))}

                    </Layer>
                </Stage>
                <ToolsContainer getCommentsHandler={comments => this.getCommentsHandler(comments)} />
                <button className="pure-button" onClick={() => this.downloadImageHandler()}>Download</button>
            </div>
        )
    }
}
export default ImageContainer;

对于那些想知道我在这个项目中使用react-konva的人。 任何帮助将不胜感激。

编辑

拖动注释将显示重复项

2 个答案:

答案 0 :(得分:1)

您的问题在这一行:

where (int(yrdif(Birthday,today(),'ACTUAL')) &p_age)
...
%detReport( p_age =between 20 and 40)
%detReport( p_age = >= 40)

当您使用扩操作你的方式,你把现有的数组内容,所有接收到的数据追加到它,像这样:

getCommentsHandler = comments => {
  console.log("[ImageContainer][getCommentsHandler] " + comments);
  this.setState(
    {
      commentsArray: [...this.state.commentsArray, ...comments]  // This is the problematic line
    },
    () => {
      console.log("[ImageContainer][getCommentsHandler] " + this.state);
    }
  );
};

您需要更改标有注释的行看起来像:

const a = [1,2];
const b = [2];
const b = [...a, ...b] // b === [1,2,2]

答案 1 :(得分:0)

可能不是最好的方法,但是它可以工作。

回调函数getCommentsHandler返回注释数组。解决此问题的方法是,在从<ImageContainer>组件中获取状态值之前,将<ToolsContainer>组件中commentArray的状态设置为空。

commentsArray: [...this.state.commentsArray, ...comments]行是导致重复问题的原因。在回调函数中,我将其替换为this.setState({ commentsArray: [] }),然后添加了this.setState({commentsArray: comments})