ReactJS:如何在父组件中使用子组件生成的finaleImg图片
问题
在子组件DropDownMenu中通过const [finaleImg] = useImage(dragUrl.current);生成了finaleImg,控制台能正常查看该图片,但在父组件App的<Rect>组件的fillPatternImage={finaleImg}属性中使用时,出现“finaleImg is not defined”的错误。
以下是相关代码:
function App() { const dragUrl = React.useRef(); const stageRef = React.useRef(); const [files, setFiles] = useState([]) const onSuccess = (savedFiles) => { setFiles(savedFiles) }; const DropDownMenu = ({ files }) => { console.log("files", files) const [value, setValue] = React.useState(''); const handleChange = (event) => { setValue(event.target.value); dragUrl.current = `//localhost:5000/${event.target.value}`; console.log("dragurl", dragUrl.current) }; const [finaleImg] = useImage(dragUrl.current); console.log("finaleImg", finaleImg) return ( <div> <label> Choose Floor <select value={value} onChange={handleChange}> {files.map((file, i) => ( <option key={i} value={file.src}>{file.filename}</option> ))} </select> </label> </div> ); } return ( <div className="App"> <div className='fileUploader'> <FileUploader onSuccess={onSuccess} /> </div> <div className='uploaded-images'> <DropDownMenu files={files} /> </div> <div className='stage'> <div> <br /> <div> <Stage width={window.innerWidth} height={window.innerHeight} style={{ border: '1px solid grey' }} ref={stageRef} > <Layer> <Rect width={window.innerWidth} height={window.innerHeight} fill="red" //fillPatternImage={finaleImg} /> </Layer> </Stage> </div> </div> </div> </div> ); } export default App;
取消注释fillPatternImage={finaleImg}时触发错误,注释后finaleImg可正常在控制台输出,请问如何正确在父组件中使用子组件生成的这张图片?
解决方案
问题核心是子组件的变量无法直接被父组件访问,要解决这个问题,需要把图片状态提升到父组件,并通过子组件的回调传递数据,具体步骤如下:
1. 在父组件App中添加图片状态
在父组件里声明存储finaleImg的状态,同时把图片URL的管理移到父组件(避免跨组件使用ref,改用状态更符合React数据流规范):
function App() { const stageRef = React.useRef(); const [files, setFiles] = useState([]); // 新增:存储选中的图片URL和生成的finaleImg const [selectedImgUrl, setSelectedImgUrl] = useState(''); const [finaleImg, setFinaleImg] = useState(null); const onSuccess = (savedFiles) => { setFiles(savedFiles); }; // 新增:监听选中URL变化,自动生成图片 useEffect(() => { if (selectedImgUrl) { const [img] = useImage(selectedImgUrl); setFinaleImg(img); } }, [selectedImgUrl]);
2. 修改子组件DropDownMenu,通过回调传递选中的URL
把父组件的setSelectedImgUrl作为props传给子组件,子组件选择下拉项时调用这个方法更新父组件的状态:
const DropDownMenu = ({ files, onSelectImg }) => { const [value, setValue] = React.useState(''); const handleChange = (event) => { const selectedSrc = event.target.value; setValue(selectedSrc); // 调用父组件回调,传递完整图片URL onSelectImg(`//localhost:5000/${selectedSrc}`); }; return ( <div> <label> Choose Floor <select value={value} onChange={handleChange}> {files.map((file, i) => ( <option key={i} value={file.src}>{file.filename}</option> ))} </select> </label> </div> ); };
3. 在父组件渲染DropDownMenu时传入回调
<DropDownMenu files={files} onSelectImg={setSelectedImgUrl} />
4. 在<Rect>组件中使用finaleImg
现在父组件拥有了finaleImg状态,直接在属性中使用即可:
<Rect width={window.innerWidth} height={window.innerHeight} fill="red" fillPatternImage={finaleImg} />
完整修改后的代码
function App() { const stageRef = React.useRef(); const [files, setFiles] = useState([]); const [selectedImgUrl, setSelectedImgUrl] = useState(''); const [finaleImg, setFinaleImg] = useState(null); const onSuccess = (savedFiles) => { setFiles(savedFiles); }; useEffect(() => { if (selectedImgUrl) { const [img] = useImage(selectedImgUrl); setFinaleImg(img); } }, [selectedImgUrl]); const DropDownMenu = ({ files, onSelectImg }) => { const [value, setValue] = React.useState(''); const handleChange = (event) => { const selectedSrc = event.target.value; setValue(selectedSrc); onSelectImg(`//localhost:5000/${selectedSrc}`); }; return ( <div> <label> Choose Floor <select value={value} onChange={handleChange}> {files.map((file, i) => ( <option key={i} value={file.src}>{file.filename}</option> ))} </select> </label> </div> ); }; return ( <div className="App"> <div className='fileUploader'> <FileUploader onSuccess={onSuccess} /> </div> <div className='uploaded-images'> <DropDownMenu files={files} onSelectImg={setSelectedImgUrl} /> </div> <div className='stage'> <div> <br /> <div> <Stage width={window.innerWidth} height={window.innerHeight} style={{ border: '1px solid grey' }} ref={stageRef} > <Layer> <Rect width={window.innerWidth} height={window.innerHeight} fill="red" fillPatternImage={finaleImg} /> </Layer> </Stage> </div> </div> </div> </div> ); } export default App;
关键说明
- 遵循React单向数据流原则:子组件通过回调把数据传递给父组件,父组件管理状态后再传递给需要使用的组件。
- 移除了跨组件的
dragUrlref,改用状态selectedImgUrl管理选中的图片URL,更符合React状态管理规范。 - 通过
useEffect监听selectedImgUrl变化,自动调用useImage生成图片并更新finaleImg状态。
内容的提问来源于stack exchange,提问作者apotamkinn
相关产品推荐
相关产品推荐

