I’m encountering an issue in my React project where a button is being rendered twice, but only the bottom button works.
If anyone has any suggestions or has seen this before, I’d appreciate your help!
import React, { useState, useEffect, useRef } from 'react';
const PixelatedImage = ({ imageUrl }) => {
const [pixelatedSections, setPixelatedSections] = useState([true, true, true, true]); // All sections pixelated initially
const canvasRef = useRef(null);
useEffect(() => {
if (!imageUrl) return; // Wait for image to load
const canvas = canvasRef.current;
const context = canvas.getContext("2d");
const img = new Image();
img.src = imageUrl;
img.onload = () => {
const width = img.width;
const height = img.height;
// Set canvas size to image size
canvas.width = width;
canvas.height = height;
const pixelateSection = (left, top, sectionWidth, sectionHeight, pixelSize = 10) => {
const offscreenCanvas = document.createElement("canvas");
const offscreenContext = offscreenCanvas.getContext("2d");
offscreenCanvas.width = sectionWidth;
offscreenCanvas.height = sectionHeight;
offscreenContext.drawImage(canvas, left, top, sectionWidth, sectionHeight, 0, 0, sectionWidth, sectionHeight);
offscreenContext.imageSmoothingEnabled = false;
offscreenContext.drawImage(offscreenCanvas, 0, 0, sectionWidth / pixelSize, sectionHeight / pixelSize);
offscreenContext.drawImage(
offscreenCanvas,
0,
0,
sectionWidth / pixelSize,
sectionHeight / pixelSize,
0,
0,
sectionWidth,
sectionHeight
);
context.drawImage(offscreenCanvas, left, top);
};
const unpixelateSection = (left, top, sectionWidth, sectionHeight) => {
context.drawImage(img, left, top, sectionWidth, sectionHeight, left, top, sectionWidth, sectionHeight);
};
const drawCanvas = () => {
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(img, 0, 0, width, height);
if (pixelatedSections[0]) pixelateSection(0, 0, width / 2, height / 2);
if (pixelatedSections[1]) pixelateSection(width / 2, 0, width / 2, height / 2);
if (pixelatedSections[2]) pixelateSection(0, height / 2, width / 2, height / 2);
if (pixelatedSections[3]) pixelateSection(width / 2, height / 2, width / 2, height / 2);
};
drawCanvas();
};
}, [imageUrl, pixelatedSections]); // Redraw whenever pixelatedSections changes
const unpixelateNextSection = () => {
const nextPixelatedSections = [...pixelatedSections];
const nextIndex = nextPixelatedSections.indexOf(true);
if (nextIndex !== -1) {
nextPixelatedSections[nextIndex] = false; // Unpixelate the first pixelated section
setPixelatedSections(nextPixelatedSections); // Update the state to trigger a re-render
}
};
return (
<div>
<canvas ref={canvasRef}></canvas>
{/* Handle button click with React's onClick */}
<button onClick={unpixelateNextSection}>Unpixelate Next Section</button>
</div>
);
};
export default PixelatedImage;
I’ve been trying to fix it with no luck so far, and here’s what I’ve attempted:
Checked the component rendering logic to make sure it's only rendering one button. Used document.getElementById and manually added event listeners, but that caused the button to render twice. Removed id and used React’s onClick event handler, but the problem still persists.
If your project uses React 18 with StrictMode
enabled, React will intentionally double-render components in development mode to detect side effects. Check if StrictMode
is enabled in index.js
or main.jsx
<React.StrictMode>
<App />
</React.StrictMode>
Try disabling StrictMode
and running the code.
Check this question for more info.