React自定义图片缩放Hook实现求助:抽离图片处理逻辑为useImage
自定义
useImage Hook实现图片上传缩放 可以将图片缩放、状态管理及异步处理逻辑封装为可复用的自定义React Hook,以下是具体实现方案:
步骤1:抽离通用辅助函数
将图片格式转换、缩放的核心逻辑单独封装,便于复用和维护:
// 将dataURL转换为File对象 function dataURLtoFile(dataurl, filename) { const arr = dataurl.split(','); const mime = arr[0].match(/:(.*?);/)[1]; const bstr = atob(arr[1]); let n = bstr.length; const u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new File([u8arr], filename, { type: mime }); } // 异步处理图片缩放,返回缩放后的File对象 async function createScaledImageFile(file, maxSize = 224, outputFilename = 'x-ray.png') { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onloadend = (event) => { const image = new Image(); image.onload = () => { const canvas = document.createElement('canvas'); let width = image.width; let height = image.height; // 计算等比缩放后的尺寸 if (width > height) { width > maxSize && (height *= maxSize / width, width = maxSize); } else { height > maxSize && (width *= maxSize / height, height = maxSize); } canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d', { alpha: false }); ctx.drawImage(image, 0, 0, width, height); const dataUrl = canvas.toDataURL('image/jpeg', 1); resolve(dataURLtoFile(dataUrl, outputFilename)); }; image.onerror = reject; image.src = event.target.result; }; reader.onerror = reject; }); }
步骤2:实现useImage自定义Hook
将状态管理和文件处理逻辑封装到Hook中,对外暴露状态和处理函数:
import { useState } from 'react'; function useImage(maxSize = 224, outputFilename = 'x-ray.png') { const [file, setFile] = useState(null); const handleChange = async (e) => { const selectedFile = e.target.files?.[0]; if (!selectedFile || !selectedFile.type.match(/image.*/)) return; try { const scaledFile = await createScaledImageFile(selectedFile, maxSize, outputFilename); setFile(scaledFile); } catch (err) { console.error('图片处理失败:', err); // 可在此添加自定义错误提示逻辑 } }; return [file, handleChange]; } export { useImage, createScaledImageFile, dataURLtoFile };
步骤3:在组件中使用Hook
在业务组件中直接调用Hook,简化代码逻辑:
import { useImage } from './path-to-your-hook'; function ImageUploadComponent() { const [scaledImageFile, handleImageChange] = useImage(224, 'x-ray.png'); // 提交至后端的逻辑 const handleSubmit = async () => { if (!scaledImageFile) return; const formData = new FormData(); formData.append('image', scaledImageFile); // 发起后端请求 // await fetch('/api/upload', { method: 'POST', body: formData }); }; return ( <div> <input type="file" accept="image/*" onChange={handleImageChange} /> <button onClick={handleSubmit} disabled={!scaledImageFile}>上传图片</button> </div> ); }
优化亮点
- 用
async/await替代多层回调,提升代码可读性 - Hook支持自定义
maxSize和outputFilename,增强复用灵活性 - 添加错误捕获逻辑,避免图片处理失败导致组件崩溃
- 辅助函数与Hook解耦,可单独用于其他场景
内容的提问来源于stack exchange,提问作者Weber Chang
相关产品推荐
相关产品推荐

