Expo/React Native集成Firebase首次选图报错:Network request failed
问题原因
- 核心问题是React Native的
useState更新为异步操作。首次选择图片时,你先调用imgFirebase(),再执行setImage(result.assets[0].uri)。此时imgFirebase里的image状态还未完成更新,仍然是初始值null,执行fetch(null)自然会抛出「Network request failed」错误。 - 后续选图时,
image状态已经留存了上一次的有效uri,所以不会触发该错误,但逻辑上仍存在隐患(可能上传的是旧图片),只是未暴露报错而已。
修复方案
直接将选中的图片uri作为参数传给imgFirebase,绕过异步状态更新的延迟问题,具体修改如下:
修改postImage函数
async function postImage () { try { let result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ImagePicker.MediaTypeOptions.All, allowsEditing: true, aspect: [4, 3], quality: 1, }); if (!result.canceled) { const selectedUri = result.assets[0].uri; imgFirebase(selectedUri); // 直接传递选中的uri setImage(selectedUri); } } catch(E) { Alert.alert( "Alert Title", "My Alert Msg 1", [ { text: "Cancel", onPress: () => console.log("Cancel Pressed"), style: "cancel" }, { text: "OK", onPress: () => console.log("OK Pressed") } ] ); } }
修改imgFirebase函数
async function imgFirebase (selectedUri) { // 接收传入的uri参数 try { console.log(selectedUri); const d = await fetch(selectedUri); const dd = await d.blob(); const fileName = selectedUri.substring(selectedUri.lastIndexOf("/")+1); const storage = getStorage(); const storageRef = ref(storage, fileName); uploadBytes(storageRef, dd).then((snapshot) => { getDownloadURL(snapshot.ref).then(async (url) => { setUrl(url); console.log(url); }).catch(e=>{ Alert.alert( "Alert Title", "My Alert Msg 2", [ { text: "Cancel", onPress: () => console.log("Cancel Pressed"), style: "cancel" }, { text: "OK", onPress: () => console.log("OK Pressed") } ] ); }); }); } catch(e) { alert(e); } }
额外优化建议
避免混用async/await和.then()语法,统一使用async/await让代码逻辑更清晰易读:
async function imgFirebase (selectedUri) { try { console.log(selectedUri); const d = await fetch(selectedUri); const dd = await d.blob(); const fileName = selectedUri.substring(selectedUri.lastIndexOf("/")+1); const storage = getStorage(); const storageRef = ref(storage, fileName); const snapshot = await uploadBytes(storageRef, dd); const url = await getDownloadURL(snapshot.ref); setUrl(url); console.log(url); } catch(e) { Alert.alert( "Alert Title", "My Alert Msg 2", [ { text: "Cancel", onPress: () => console.log("Cancel Pressed"), style: "cancel" }, { text: "OK", onPress: () => console.log("OK Pressed") } ] ); } }
内容的提问来源于stack exchange,提问作者Yefim Blokh
相关产品推荐
相关产品推荐

