功能组件一次又一次重新渲染时如何避免闪烁/

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

我需要帮助修复代码以防止 Iphone 图像闪烁。我已经实现了各种东西,例如 useMemo 和 useLayout 和 debounce 和

requestAnimationFrame
但我仍然面临问题

// i have imported useMemo, useRef, useCallback from React
import React, { useState, useMemo, useRef, useCallback } from "react";
import "./Iphone.css";
// I have imported debounce from lodash

import debounce from "lodash.debounce";

// I have created functional component called IPhone

const Iphone = () => {
  // I have used selectedImage and OldImage variable here and initialized them to `null`

  // I have used useMemo on initial loading of page to prevent flashing
  const image = useMemo(() => new Image(), []);
  // I have used useCallback function on initial loading of the page to handleImageChange function 

  // to change a image I called handleImageChange function

  const handleImageChange = useCallback((event) => {
    event.preventDefault();
    const newImageURL = URL.createObjectURL(event.target.files[0]);
    // i have passed newIMageURL to both SetSelectedImage and SetOldImage
    setSelectedImage(newImageURL);
    setOldImage(newImageURL);
  }, []);

  // I have called the function handleText to toggle showing of text
  const handleText = () => {
    setShowText(!showText);
  };

  // I have called useMemo function to prevent flashing as i drag the text to 
  various 
  locations
  const debouncedShowContent = useMemo(
    () => debounce((value) => setContent(value), 300),
    []
  );

  // i have called useCallback function to prevent flashing in handleDragStart 
  function

  const handleDragStart = useCallback(() => {

    // here I am setting dragging to true as i am starting to drag the text
    setDragging(true);
  }, []);
  
  // I have called useCallback function to prevent flashing in handleDrag function

  const handleDrag = useCallback(
    (e) => {
      // i am checking if dragging is true
      if (dragging) {

        // i am calling requestAnimation Frame here

        requestAnimationFrame(() => {

           // I am getting value of canvas via canvasRef.current

          const canvas = canvasRef.current;
          // i am saving value in ctx    
          const ctx = canvas.getContext("2d");
          // i am getting dimensions using canvas.getBoundingClientRect and saving it 
             in rect 
          const rect = canvas.getBoundingClientRect();
          // i am getting value of e.clientX - rect.left and saving it in x variable
          const x = e.clientX - rect.left;
          // i am getting value of e.clientY - rect.top and saving it in y variable
          const y = e.clientY - rect.top;
          // clearing the values of ctx via ctx.clearRect
          ctx.clearRect(0, 0, canvas.width, canvas.height);
           // i am inserting value into image the value oldImage
          image.src = oldImage;
          // on loading of image i am setting value in canvas
          image.onload = () => {
           // drawing image using ctx.drawImage
          ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
          // i am using ctx.fillText to fill the text with value of content and x and 
            y
          ctx.fillText(content, x, y);
             I am setting position of x and y via setPosition
          setPosition({ x, y });
          // converting the value of image to text
          const dataURI = canvas.toDataURL("image/png");
            // saving in setSelectedImage the value of dataURI
          setSelectedImage(dataURI);
          };
        });
      }
    },
    [dragging, oldImage, content]
  );

  // i have called useCallback function to prevent flashing in handleDragEnd 
     function

  const handleDragEnd = useCallback(() => {
    // i am setting the position in x and y via position.x and position.y
    setPosition({ x: position.x, y: position.y });
    // i am setting dragging to false
    setDragging(false);
  }, [position]);

  // i have called useCallback function to prevent flashing in addText function

  const addText = useCallback(() => {
    // here i am setting the image to be true
    setShowImage(true);
     // if image is not selected then do return;
    if (!selectedImage || !content) return;
    textDrawn.current = true;
    requestAnimationFrame(() => {
     // I am getting value of canvas via canvasRef.current
      const canvas = canvasRef.current;
     // i am saving value in ctx    
      const ctx = canvas.getContext("2d");
      // i am inserting value into image the value selectedImage
      image.src = selectedImage;

      // on loading of image i am setting value in canvas
      image.onload = () => {
        // getting width of canvas from image.width
        canvas.width = image.width;
        // getting height of canvas from image.height
        canvas.height = image.height;
        // clearing the values of ctx via ctx.clearRect
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        // drawing image using ctx.drawImage
        ctx.drawImage(image, 0, 0);
        // i am using ctx.fillText to fill the text with value of content
        ctx.fillText(content, textPosition.x, textPosition.y);
        // converting the value of image to text
        const dataURI = canvas.toDataURL("image/png");
        // saving in setSelectedImage the value of dataURI
        setSelectedImage(dataURI);
      };
    });
  }, [selectedImage, content, textPosition]);
  
  // i have used debouncedShowContent function to prevent flashing in showContent 
     function
 
  const showContent = (event) => {
    // calling debouncedShowContent
    debouncedShowContent(event.target.value);
  };
   
  // I am using handleSave function to save the image along with text in new 
  window
  const handleSave = () => { 

    // if image is selected then I am opening new window
    if (selectedImage) {
      // opening a new window
      const newWindow = window.open();
      // writing a new image 
      newWindow.document.write(
        `<img src="${selectedImage}" alt="resultingImage" />`
      );
    }
  };
   // i want to add more details. if you have any questions ask and i will clarify 
      quickly.
};

// I am exporting the Iphone function
export default Iphone;

当我将文本从一个位置拖动到另一个位置时,我想防止图像闪烁。怎么办?

我可以添加更多细节。如果您有任何疑问,请提出,我会尽快澄清。

我已经在每一行代码中发表了注释。我还应该做些什么来改善这个问题吗?

reactjs iphone canvas react-hooks lodash
1个回答
0
投票

我将重点关注

handleDrag
功能...

删除所有评论,这就是我们得到的:

    requestAnimationFrame(() => {
      const canvas = canvasRef.current;
      const ctx = canvas.getContext("2d");
      const rect = canvas.getBoundingClientRect();
      const x = e.clientX - rect.left;
      const y = e.clientY - rect.top;
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      image.src = oldImage;
      image.onload = () => {
        ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
        ctx.fillText(content, x, y);
        setPosition({ x, y });
        const dataURI = canvas.toDataURL("image/png");
        setSelectedImage(dataURI);
      };
    });

首先突出的是常量

canvas
ctx
rect
,您应该将它们移至全局常量,无需每次调用拖动函数或与绘图相关的任何其他函数时都实例化它们

其次,这个函数中有

image.onload
,我不认为
oldImage
每次都会改变值,最好在这个函数之外执行此操作,使图像成为全局常量

© www.soinside.com 2019 - 2024. All rights reserved.