React Native Expo项目中如何从Firebase获取并展示存储的图片
错误原因
- 混淆了函数组件
useState和类组件this.state的用法:你在函数组件中用useState存储状态,却用this.state.profileImageUrl读取变量,该变量不存在所以直接报错。 - 状态变量和组件重名:存储图片的状态变量命名为
Image,和React Native原生的Image组件重名,会引发渲染异常。 - 存储url的逻辑错误:调用
setImage时将实际url变量套了引号变成了固定字符串'url',且存储的key为profileimageUrl(全小写开头),读取时用的是驼峰命名profileImageUrl,大小写不一致无法正常取值。 - 上传逻辑没有持久化存储url:上传完成后仅打印了url,没有存储到全局状态、本地存储等可跨页面访问的位置,第二个页面无法直接拿到上传后的地址。
Image组件属性写法错误:source属性需要传入{uri: 图片链接}格式的对象,不能直接填入url字符串。- 获取url的逻辑没有放在生命周期钩子中:直接写在组件顶层会在每次组件渲染时重复执行,需要放在
useEffect中限制仅挂载时执行一次。
修复代码
上传逻辑修改
// 需先安装@react-native-async-storage/async-storage用于跨页面存地址 import AsyncStorage from '@react-native-async-storage/async-storage'; const uploadImage = async () => { const blob = await new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.onload = function () { resolve(xhr.response); }; xhr.onerror = function () { // 修复原代码的拼写错误oneerror -> onerror reject(new TypeError('Network request failed')); }; xhr.responseType = 'blob'; xhr.open('GET', image, true); xhr.send(null); }); // 文件名添加时间戳避免多次上传覆盖同一文件 const ref = firebase.storage().ref().child(`/ankit/${Date.now()}.jpg`); const snapshot = ref.put(blob); snapshot.on( firebase.storage.TaskEvent.STATE_CHANGED, () => { setUploading(true); }, (error) => { setUploading(false); console.log(error); blob.close(); }, async () => { const url = await snapshot.snapshot.ref.getDownloadURL(); setUploading(false); console.log('download url', url); // 将上传后的url存在本地存储,供第二个页面读取 await AsyncStorage.setItem('profileImageUrl', url); } ); };
第二页展示逻辑修改
import { useEffect, useState } from 'react'; import { View, Image } from 'react-native'; import AsyncStorage from '@react-native-async-storage/async-storage'; const SecondPage = () => { // 单独定义状态存储图片url,避免和组件重名 const [profileImageUrl, setProfileImageUrl] = useState(null); useEffect(() => { // 从本地存储读取之前上传的图片地址 const getSavedImage = async () => { const savedUrl = await AsyncStorage.getItem('profileImageUrl'); if (savedUrl) setProfileImageUrl(savedUrl); }; getSavedImage(); // 如果你需要直接从Firebase拉取固定路径的文件,用下面的逻辑,注意路径要和上传的路径完全一致 /* const imageRef = firebase.storage().ref('/ankit/你的具体文件名.jpg'); imageRef.getDownloadURL() .then(url => setProfileImageUrl(url)) .catch(e => console.log('获取图片地址失败:', e)) */ }, []); return ( <View> {/* 判空后再渲染图片,避免加载报错,必须指定宽高才能正常显示网络图片 */} {profileImageUrl && ( <Image source={{ uri: profileImageUrl }} style={{ width: 200, height: 200 }} /> )} </View> ); }; export default SecondPage;
内容的提问来源于stack exchange,提问作者Ankit Verma
相关产品推荐
相关产品推荐

