在函数内和函数外获取不同的值 REACT.JS

问题描述 投票:0回答:0

我刚刚开始我的软件开发生涯。我在获取正确的值方面遇到问题。

我有一个组件,我从父组件中获取图像标签作为道具。在子组件中,标签被正确传递。但是每次我尝试在函数中使用 etag 时, this 的值只是第一次渲染页面后获得的初始值。

为什么会发生这种情况以及如何解决此问题?

这是我的代码片段:


<AnnotationCanvas
          imagePath={imagePath}
          imgEtag={imgEtag}
          imageData={imageData}
        />

AnnotationCanvas.js:

import React, { useEffect, useRef, useState, useCallback } from "react";
// Material UI stuff
import BrushOutlinedIcon from "@mui/icons-material/BrushOutlined";
import RectangleOutlinedIcon from "@mui/icons-material/RectangleOutlined";
import AllOutOutlinedIcon from "@mui/icons-material/AllOutOutlined";
import MouseIcon from "@mui/icons-material/Mouse";
import DeleteForeverOutlinedIcon from "@mui/icons-material/DeleteForeverOutlined";
import AdsClickOutlinedIcon from "@mui/icons-material/AdsClickOutlined";
import NoteAddOutlinedIcon from "@mui/icons-material/NoteAddOutlined";
import { HighlightAltOutlined } from "@mui/icons-material";
import {
  Paper,
  Switch,
  Typography,
  Button,
  Rating,
  List,
  Tooltip,
  ListItemButton,
  Divider,
  ListItem,
  ListItemIcon,
  ListItemText,
  MenuItem,
  IconButton,
  Menu,
} from "@mui/material";
import { makeStyles } from "@mui/styles";
import { motion } from "framer-motion";

import paper from "paper";

import { useLocation, useNavigate } from "react-router-dom";
// translation
import { useTranslation } from "react-i18next";
import { createAnnotation, createOrGetImage } from "src/app/api/api";

const useStyles = makeStyles({
  crosshairCursor: {
    cursor: "crosshair",
  },
  defaultCursor: {
    cursor: "default",
  },
  annotationList: {
    height: "150px",
    top: "150px",
  },
});

// setting color variables
const transparentBlue = "#6A59FF47";
const transparentRed = "#f7021280";

const AnnotationCanvas = ({ imagePath, imgEtag, imageData }) => {
  // global variables & states
  const { t } = useTranslation("Annotexray");
  const location = useLocation();
  const classes = useStyles();
  const canvasRef = useRef(null);
  const [rect, setRect] = useState(null);
  let finalCircle;
  let temporareCircle;

  //   toolbox states
  const [circleClicked, setCircleClicked] = useState(false);
  const [polygonClicked, setPolygonClicked] = useState(false);
  const [cursor, setCursor] = useState(false);

  // states to save data
  const [imgData, setImgData] = useState();
  const [image, setImage] = useState();
  const [annotationsState, setAnnotationsState] = useState([]);
  const [startPos, setStartPos] = useState({ x: 0, y: 0 });
  let getMiddleOfX;
  let getMiddleOfY;
  // const [circle, setCircle] = useState()
  // Switching Cursor mode
  const switchCursor = () => {
    setCursor((prevState) => !prevState);
  };
  const getInitialData = async (imgEtag) => {
    try {
      const path = location.state.content.Key;
      const { data } = await createOrGetImage(imgEtag, path);
      setImage(data.imageRawData);
      setImgData(data.imageDBData);
      const img = new Image();
      img.src = data.imageRawData;
      img.onload = () => {
        // eslint-disable-next-line
        const width = img.width;
        // eslint-disable-next-line
        const height = img.height;
        console.log(data.imageDBData)
        setAnnotationsState(data.imageDBData.annotations);
      };
    } catch (error) {
      console.log("ERROR AT GETINITIALDATA ", error);
    }
  };

  const handleBackToMouse = () => {
    setCircleClicked(false);
    setCursor(false);
  };

  const handleCircle = () => {
    setCircleClicked((prevState) => !prevState);
  };
  useEffect(() => {
    getInitialData(imgEtag);
  }, [imgEtag]);

  const createCircle = () => {};
  useEffect(() => {
    if (image && canvasRef.current) {
      const canvas = canvasRef.current;
      paper.setup(canvas);
      const raster = new paper.Raster(image);
      raster.position = paper.view.center;
      raster.size = [900, 650];
      const layer = paper.project.activeLayer;
      layer.addChild(raster);
      setRect(canvas.getBoundingClientRect());
    }
  }, [image, imgEtag]);
  // render annotations from BE
  useEffect(() => {
    if (annotationsState.length > 0) {
      // eslint-disable-next-line
      annotationsState.map((annotation) => {
        // loading Circles from BE
        if (annotation.shape === "circle") {
          console.log("CIRCLE TRIGGERED");
          const xPoint = Number(annotation.center[0]);
          const yPoint = Number(annotation.center[1]);
          finalCircle = new paper.Path.Circle({
            center: new paper.Point(xPoint, yPoint),
            radius: annotation.size,
            fillColor: transparentBlue,
            selected: true,
          });
          paper.project.activeLayer.addChild(finalCircle);
        }
      });
    }
  }, [annotationsState]);
  let circle;
  let circleRadius;
console.log("IMAGE ETAG", imgEtag)
  const handleCircleMouseUp = (event) => {
    event.preventDefault();
    // temporareCircle.remove();
    finalCircle = new paper.Path.Circle({
      center: new paper.Point(getMiddleOfX, getMiddleOfY),
      radius: circleRadius / 2,
      fillColor: transparentRed,
    });
    paper.view.update();
    document
      .getElementById("annotationCanvas")
      .removeEventListener("mouseup", handleCircleMouseUp);
    document
      .getElementById("annotationCanvas")
      .removeEventListener("mousemove", handleCircleMouseMove);
      console.log("IMGETAG ", imgEtag)
      try {
        console.log("ETAG ",location.state)
        const { data } =  createOrGetImage(imgEtag, location.state.content.Key).then((res) => res.data);
        const updateAnnotationObj = {
          imageID: data.imageDBData._id,
          annotationObj: {
            color: transparentBlue,
            borderColor: "green",
            center: [getMiddleOfX, getMiddleOfY],
            size: circleRadius / 2,
            shape: "circle"
          }
        };
        console.log(updateAnnotationObj);
      const updatedAnnotation = createAnnotation(updateAnnotationObj).then((res) => res.data)
      setAnnotationsState((prevState) => [
        ...prevState,
        updatedAnnotation.data
      ])
    } catch (error) {}
  };

  const handleCircleMouseMove = (event) => {
    event.preventDefault();
    getMiddleOfX = (startPos.x + (event.clientX - rect.left)) / 2;
    getMiddleOfY = (startPos.y + (event.clientY - rect.top)) / 2;
    // calculate Radius
    circleRadius = new paper.Point(startPos.x, startPos.y).getDistance(
      event.clientX - rect.left,
      event.clientY - rect.top
    );

    // creating temporare circle
    circle = new paper.Path.Circle({
      center: new paper.Point(getMiddleOfX, getMiddleOfY),
      radius: circleRadius / 2,
      fillColor: new paper.Color(transparentBlue),
    });
    if (temporareCircle) {
      temporareCircle.remove();
    }
    temporareCircle = circle;
    document
      .getElementById("annotationCanvas")
      .addEventListener("mouseup", handleCircleMouseUp);
  };

  const handleCircleMouseDown = ((event) => {
    event.preventDefault();

    startPos.x = event.clientX - rect.left;
    startPos.y = event.clientY - rect.top;
    document
      .getElementById("annotationCanvas")
      .addEventListener("mousemove", handleCircleMouseMove);
  });

  useEffect(() => {
    if (circleClicked && canvasRef.current) {
      document
        .getElementById("annotationCanvas")
        .addEventListener("mousedown", handleCircleMouseDown);
    }
    return () => {
      if (canvasRef.current) {
        document
          .getElementById("annotationCanvas")
          .removeEventListener("mousedown", handleCircleMouseDown);
      }
    };
  }, [circleClicked]);

  return (
    <motion.div
      className="grid grid-cols-3  w-full"
      style={{ gridTemplateColumns: "10% 60% 30%" }}
    >
      {/* START TOOLBOX */}
      <motion.div className="grid grid-rows-1 align-center p-24 m-24 justify-center items-center">
        <motion.div
          className="grid grid-cols-1 items-center justify-center align-center"
          style={{ paddingBottom: "30px" }}
        >
          <Paper
            className="shadow rounded-2xl overflow-hidden"
            sx={{ width: "55px" }}
          >
            <List>
              <Tooltip title={t("MOUSE")} arrow>
                <ListItemButton onClick={handleBackToMouse}>
                  <MouseIcon />
                </ListItemButton>
              </Tooltip>
              <Divider />
              <Tooltip title={t("SWITCHCURSOR")} arrow>
                <ListItemButton
                  style={{
                    boxShadow: cursor
                      ? "0px 2px 4px -1px rgba(0,0,0,0.2), 0px 4px 5px 0px rgba(0,0,0,0.14), 0px 1px 10px 0px rgba(0,0,0,0.12)"
                      : "none",
                    transform: cursor ? "scale(0.98)" : "scale(1)",
                    color: cursor && "blue",
                  }}
                  onClick={switchCursor}
                >
                  <AdsClickOutlinedIcon />
                </ListItemButton>
              </Tooltip>
              <Divider />
              <Tooltip title={t("BRUSH")} arrow>
                <ListItemButton disabled>
                  <BrushOutlinedIcon />
                </ListItemButton>
              </Tooltip>
              <Divider />
              <Tooltip title={t("BOUNDINGBOX")} arrow>
                <ListItemButton
                  // style={{
                  //   boxShadow: boundingBoxClicked
                  //     ? "0px 2px 4px -1px rgba(0,0,0,0.2), 0px 4px 5px 0px rgba(0,0,0,0.14), 0px 1px 10px 0px rgba(0,0,0,0.12)"
                  //     : "none",
                  //   transform: boundingBoxClicked
                  //     ? "scale(0.98)"
                  //     : "scale(1)",
                  //   color: boundingBoxClicked && "blue",
                  // }}
                  disabled
                  // onClick={() => handleBoundingBox()}
                >
                  <RectangleOutlinedIcon />
                </ListItemButton>
              </Tooltip>
              <Divider />
              <Tooltip title={t("POLYGON")} arrow>
                <ListItemButton
                  style={{
                    boxShadow: polygonClicked
                      ? "0px 2px 4px -1px rgba(0,0,0,0.2), 0px 4px 5px 0px rgba(0,0,0,0.14), 0px 1px 10px 0px rgba(0,0,0,0.12)"
                      : "none",
                    transform: polygonClicked ? "scale(0.98)" : "scale(1)",
                    color: polygonClicked && "blue",
                  }}
                  // onClick={() => handlePolygon()}
                >
                  <HighlightAltOutlined />
                </ListItemButton>
              </Tooltip>
              <Divider />
              <Tooltip title={t("CIRCLESHAPE")} arrow>
                <ListItemButton
                  style={{
                    boxShadow: circleClicked
                      ? "0px 2px 4px -1px rgba(0,0,0,0.2), 0px 4px 5px 0px rgba(0,0,0,0.14), 0px 1px 10px 0px rgba(0,0,0,0.12)"
                      : "none",
                    transform: circleClicked ? "scale(0.98)" : "scale(1)",
                    color: circleClicked && "blue",
                  }}
                  onClick={() => handleCircle()}
                >
                  <AllOutOutlinedIcon />
                </ListItemButton>
              </Tooltip>
              {/* TODO: Change this functionality to a delete all functionality */}
              {/* <Divider />
                <Tooltip title={t("DELETE")} arrow>
                  <ListItemButton
                    disabled={annotationsState && annotationsState.length === 0}
                    onClick={handleDeleteLastAnnotation}
                  >
                    <DeleteForeverOutlinedIcon />
                  </ListItemButton>
                </Tooltip> */}
            </List>
          </Paper>
        </motion.div>
      </motion.div>
      {/* END OF TOOLBOX */}
      <motion.div className="w-full p-24">
        <canvas
          ref={canvasRef}
          id="annotationCanvas"
          className={cursor ? classes.crosshairCursor : classes.defaultCursor}
          style={{ width: 900, height: 650 }}
        />
      </motion.div>
      {/* START OF ANNOTATIONSWIDGET */}
      <motion.div>
        <Paper
          className={`flex flex-col flex-auto p-24 shadow rounded-2x1 overflow-auto ${classes.annotationList}`}
        >
          <motion.div>
            <Typography
              className="px-16 text-lg font-medium tracking-tight leading-6 truncate"
              color="text.secondary"
            >
              {t("ANNOTATIONS")}
            </Typography>
          </motion.div>
          <motion.div className="flex flex-col items-center">
            <List className="w-5/6">
              {annotationsState && annotationsState.length > 0 ? (
                annotationsState.map((annotation, index) => {
                  let annotationIcon;
                  if (annotation.shape === "polygon") {
                    annotationIcon = <HighlightAltOutlined />;
                  } else if (annotation.shape === "circle") {
                    annotationIcon = <AllOutOutlinedIcon />;
                  }
                  return (
                    <motion.div key={index}>
                      <ListItem key={index} disablePadding>
                        <ListItemIcon>{annotationIcon}</ListItemIcon>
                        <ListItemText
                          primary={
                            <Typography
                              variant="body1"
                              style={{
                                fontWeight: "bold",
                              }}
                            >
                              {`${index + 1}.${
                                annotation.tag === undefined
                                  ? "unknown"
                                  : annotation.tag
                              }`}
                            </Typography>
                          }
                        />

                        <ListItemIcon style={{ color: "red" }}>
                          <ListItemButton
                          // onClick={() => handleDeleteLastAnnotation(index)}
                          >
                            <DeleteForeverOutlinedIcon />
                          </ListItemButton>
                        </ListItemIcon>
                      </ListItem>
                      {index !== annotationsState.length - 1 && <Divider />}
                    </motion.div>
                  );
                })
              ) : (
                <motion.div>{t("NOANNOTATIONS")}</motion.div>
              )}
            </List>
          </motion.div>
        </Paper>
      </motion.div>
      {/* END OF ANNOTATIONSWIDGET */}
    </motion.div>
  );
};

export default AnnotationCanvas;

我在handleCricleMouseUp函数之外得到的值是正确的,但是这个函数中的值是旧值。

希望我能尽快得到你们的帮助,我花了一周时间试图找出为什么会发生这种情况。

我尝试将值保存在状态中,而不是将其作为道具获取 - 不起作用 我尝试将该值作为道具传递,但它只是不以同样的方式工作

javascript reactjs closures react-props react-state
© www.soinside.com 2019 - 2024. All rights reserved.