如何在React中搭配FileReader传入的props使用P5的loadImage()方法
核心问题排查
- 第一,你当前FileInput组件只把「文件名」传递给了父组件P5Lasso,但
p5.loadImage需要的是可访问的资源路径/Base64 DataURL,本地选中的文件光靠文件名无法被直接加载,你已经在FileInput里生成了DataURL,应该把这个值传给父组件而不是文件名。 - 第二,react-p5的setup函数只会在组件初始化时执行一次,你初始状态image是null,首次setup运行时根本没有可用的图片地址,后续更新image状态也不会触发重新加载图片的逻辑。
- 第三,load状态的判断逻辑是同步执行的,而
p5.loadImage是异步方法,你在调用loadImage之后立刻判断img是否为null,这时候异步加载还没完成,永远拿不到正确的加载状态。
修正后的FileInput组件代码
import React, { useState, useRef } from 'react'; export default function FileInput(props) { const [src, setSrc]= useState(null); const fileInput = useRef(null); const handleImageSelection = (event) => { const file = event.target.files[0]; const reader = new FileReader(); reader.onload = function (e) { const dataUrl = e.target.result; setSrc(dataUrl); // 把生成的DataURL传给父组件,而不是文件名 props.selectImage(dataUrl); }; reader.readAsDataURL(file); }; const openFileInput = () => { fileInput.current.click(); }; return ( <div className="image-input" onClick={openFileInput} style={{ width: "100%", height: "400px", border: "2px solid", borderRadius: "5px", color: "black", }} > <img style={{ height: "100%" }} className="loaded-image" src={src} alt="" /> <label> <input ref={fileInput} style={{ display: "none" }} type="file" accept="image/*" onChange={handleImageSelection} /> </label> </div> ); }
修正后的P5Lasso组件代码
import React from 'react'; import Sketch from 'react-p5'; import FileInput from '../FileInput'; export default function P5Lasso(){ const [imageDataUrl, setImageDataUrl] = React.useState(null); const [p5Instance, setP5Instance] = React.useState(null); const [loadedImg, setLoadedImg] = React.useState(null); function setup(p5, canvasParentRef) { // 保存p5实例,后续更新图片的时候可以调用 setP5Instance(p5); p5.createCanvas(600, 600).parent(canvasParentRef); } function draw(p5) { // 图片加载完成后再绘制 if(loadedImg) { p5.image(loadedImg, 0, 0); } // 其余draw逻辑写在这里 } // 监听图片地址变化,自动触发加载逻辑 React.useEffect(() => { if(!p5Instance || !imageDataUrl) return; p5Instance.loadImage(imageDataUrl, (img) => { setLoadedImg(img); console.log('图片加载成功'); }, (err) => { console.log('图片加载失败', err); }); }, [p5Instance, imageDataUrl]); return ( <div> <FileInput selectImage={(dataUrl) => setImageDataUrl(dataUrl)} /> <div> <Sketch setup={setup} draw={draw} /> </div> </div> ); }
补充说明
如果需要自定义文件选择按钮的样式,直接修改FileInput组件里image-input对应的样式即可,不需要使用P5自带的createFileReader方法,完全可以用自定义的文件选择逻辑配合p5.loadImage加载DataURL实现需求。
内容的提问来源于stack exchange,提问作者Jie-Liang Lin
相关产品推荐
相关产品推荐

