Next.js中如何将<img>标签替换为新版Image组件
解决Next.js Image组件替换img后的构造错误
问题场景
将图片上传预览组件中的原生<img>替换为Next.js最新版Image组件后,出现错误:
TypeError: Failed to construct 'Image': Please use the 'new' operator, this DOM object constructor cannot be called as a function
错误原因
- 未导入Next.js Image组件:代码中使用
<Image>标签但未从next/image导入,浏览器将其识别为原生DOM的Image构造函数,触发调用方式错误。 - Next.js Image属性要求:最新版Image组件对本地/Base64格式图片需额外配置,且默认需要
width/height属性,或使用fill模式适配父容器布局。
修复步骤
- 导入Next.js官方Image组件
- 针对Base64预览图设置
unoptimized={true},禁用不必要的远程图片优化 - 使用
fill模式配合父容器的相对定位,保持原有的自适应尺寸和图片适配效果
完整修复代码
import React, { useState, useRef, useEffect } from "react"; // 导入Next.js Image组件 import Image from "next/image"; const ImageUploadCard = () => { const componentRef = useRef(null); const [componentWidth, setComponentWidth] = useState(0); const [componentHeight, setComponentHeight] = useState(0); useEffect(() => { function updateComponentWidth() { if (componentRef.current) { const width = componentRef.current.getBoundingClientRect().width; const height = componentRef.current.getBoundingClientRect().height; setComponentWidth(width); setComponentHeight(height); } } updateComponentWidth(); window.addEventListener("resize", updateComponentWidth); return () => window.removeEventListener("resize", updateComponentWidth); }, []); const inputRef = useRef(null); const [previewImage, setPreviewImage] = useState(null); const handleImageChange = (event) => { const file = event.target.files[0]; if (file && file.size > 5242880) { console.log("File size exceeds the maximum limit (5MB)"); return; } if (file) { const reader = new FileReader(); reader.onloadend = () => setPreviewImage(reader.result); reader.readAsDataURL(file); } else { setPreviewImage(null); } }; return ( <div ref={componentRef} className="mb-6 md:pr-2"> <div style={{ width: componentWidth }} className="dark:bg-jacarta-700 dark:border-jacarta-600 border-jacarta-100 group relative flex flex-col items-center justify-center rounded-lg border-2 border-dashed bg-white py-20 px-5 text-center" onClick={() => inputRef.current.click()} > <div className="relative z-10 cursor-pointer"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" className="fill-jacarta-500 mb-4 inline-block dark:fill-white" > <path fill="none" d="M0 0h24v24H0z" /> <path d="M16 13l6.964 4.062-2.973.85 2.125 3.681-1.732 1-2.125-3.68-2.223 2.15L16 13zm-2-7h2v2h5a1 1 0 0 1 1 1v4h-2v-3H10v10h4v2H9a1 1 0 0 1-1-1v-5H6v-2h2V9a1 1 0 0 1 1-1h5V6zM4 14v2H2v-2h2zm0-4v2H2v-2h2zm0-4v2H2V6h2zm0-4v2H2V2h2zm4 0v2H6V2h2zm4 0v2h-2V2h2zm4 0v2h-2V2h2z" /> </svg> <p className="dark:text-jacarta-300 mx-auto max-w-xs text-xs"> Image formats: JPEG, PNG, JPG . Max size: 5 MB </p> <label> <input type="file" accept=".jpg, .jpeg, .png" onChange={handleImageChange} style={{ display: "none" }} ref={inputRef} max="5242880" /> </label> </div> </div> {previewImage && ( <div className="dark:bg-jacarta-700 dark:border-jacarta-600 border-jacarta-100 group relative flex items-center justify-center rounded-lg border-2 border-dashed bg-white py-20 px-5 text-center" style={{ width: componentWidth, height: 400 }} > <Image src={previewImage} alt="Preview" fill unoptimized={true} style={{ objectFit: "cover" }} /> </div> )} </div> ); }; export default ImageUploadCard;
关键说明
fill属性让Image组件填充整个父容器,依赖父容器的relative定位(已通过className实现)unoptimized={true}针对Base64图片禁用Next.js的远程优化逻辑,避免无效处理- 完整保留了原有的文件大小校验、动态宽度计算等所有业务逻辑
内容的提问来源于stack exchange,提问作者Shahryar Rafique
相关产品推荐
相关产品推荐

