在 Firebase 存储中上传并获取 link 以将其添加到实时数据库中
Upload in Firebase Storage and fetch link to add it in Realtime Database
我在这个应用程序中使用了 Firebase 实时数据库和 Firebase 存储,目标是在 Firebase 存储中上传 pictures
数组中的图像,然后获取 Firebase 的 link存储到该图像并将其添加到将在 imagesUriArray
中推送并添加到实时数据库的对象中。问题是当我按下 addItem
它成功更新了 id,但 images
参数仍然为空。事实上,除非我刷新屏幕,否则 imagesUriArray
仍然是空的。
export default function NewItem({ route, navigation }) {
const [pictures, setPictures] = useState([]);
const [imagesUriArray, setImageUriArray] = useState([]);
useEffect(() => {
navigation.setOptions({
headerRight: () => (
<TouchableOpacity onPress={addItem}>
<Text style={{fontWeight:'bold'}}>ADD ITEM</Text>
</TouchableOpacity>
)
})
})
const addItem = async () => {
uploadImages()
const changes = ref(db, path)
get(changes).then(async (snapshot) => {
if (snapshot.val().data !== undefined) {
const fetchedArray = snapshot.val().data
let array = fetchedArray;
let object = {
"id": `${Math.random()}`,
"images": imagesUriArray,
}
array.push(object)
update(changes, {
data: array
})
}
})
}
}
const uploadImages = () => {
const metadata = {
contentType: 'image/jpeg',
};
pictures.forEach( async (obj) => {
const id = obj.id
const uri = obj.uri
const response = await fetch(uri);
const blob = await response.blob();
var ref = storageUpload(storage, path)
await uploadBytes(ref, blob, metadata)
await getDownloadURL(ref)
.then((metadata) => {
let array = imagesUriArray
let object = {
"id": id,
"uri": metadata
}
array.push(object)
setImageUriArray(array)
})
.catch((error) => {
console.log(error)
});
})
}
return(
..............
)
}
问题
这似乎是 uploadImages
回调中的状态突变。对 imagesUriArray
状态的引用在本地缓存,变异( 即直接推入数组 ),然后将相同的引用保存回状态。这不会触发对任何更新的状态值重新呈现的反应。
const uploadImages = () => {
...
pictures.forEach( async (obj) => {
const id = obj.id
const uri = obj.uri
const response = await fetch(uri);
const blob = await response.blob();
var ref = storageUpload(storage, path)
await uploadBytes(ref, blob, metadata)
await getDownloadURL(ref)
.then((metadata) => {
let array = imagesUriArray // <-- reference to state
let object = {
"id": id,
"uri": metadata
}
array.push(object) // <-- state mutation
setImageUriArray(array) // <-- same state reference
})
.catch((error) => {
console.log(error)
});
})
};
解决方案
使用功能状态更新从以前的状态更新。创建先前状态的浅表副本并附加新数据。
const uploadImages = () => {
...
pictures.forEach( async (obj) => {
const { id, uri } = obj;
const response = await fetch(uri);
const blob = await response.blob();
const ref = storageUpload(storage, path);
await uploadBytes(ref, blob, metadata);
await getDownloadURL(ref)
.then((uri) => {
setImageUriArray(imagesUriArray => [
... imagesUriArray, // <-- shallow copy
{ id, uri }, // <-- append new object
]);
})
.catch(console.log);
})
};
更新
uploadImages
需要 return 一个 Promise,以便 addItem
可以等待它完成其异步代码。 addItem
还需要访问 uploadImages
更新的 imagesUriArray
。
将 pictures
数组映射到最终 return s 具有 id
和新的 uri
属性的对象。
const uploadImages = () => {
...
const fetchImageUri = async ({ id, uri }) => {
try {
const response = await fetch(uri);
const blob = await response.blob();
const ref = storageUpload(storage, path);
await uploadBytes(ref, blob, metadata);
const newUri = await getDownloadURL(ref);
return { id, uri: newUrl };
} catch(error) {
console.log(error);
}
}
return Promise.all(pictures.map(fetchImageUri));
};
更新 addItem
以等待包含已上传图像数据的已解析 Promise 数组。将 imagesUriArray
状态更新排入队列,然后继续引用 uploadImages
.
中 returned uploadedImages
数组的其余函数
const addItem = async () => {
const uploadedImages = await uploadImages();
setImageUriArray(imagesUriArray => [
...imagesUriArray, // <-- shallow copy
...uploadedImages, // <-- append new objects
]);
const changes = ref(db, path);
get(changes).then(async (snapshot) => {
if (snapshot.val().data !== undefined) {
const fetchedArray = snapshot.val().data;
const object = {
id: `${Math.random()}`,
images: uploadedImages,
};
update(changes, { data: [...fetchedArray, object] });
}
});
}
我在这个应用程序中使用了 Firebase 实时数据库和 Firebase 存储,目标是在 Firebase 存储中上传 pictures
数组中的图像,然后获取 Firebase 的 link存储到该图像并将其添加到将在 imagesUriArray
中推送并添加到实时数据库的对象中。问题是当我按下 addItem
它成功更新了 id,但 images
参数仍然为空。事实上,除非我刷新屏幕,否则 imagesUriArray
仍然是空的。
export default function NewItem({ route, navigation }) {
const [pictures, setPictures] = useState([]);
const [imagesUriArray, setImageUriArray] = useState([]);
useEffect(() => {
navigation.setOptions({
headerRight: () => (
<TouchableOpacity onPress={addItem}>
<Text style={{fontWeight:'bold'}}>ADD ITEM</Text>
</TouchableOpacity>
)
})
})
const addItem = async () => {
uploadImages()
const changes = ref(db, path)
get(changes).then(async (snapshot) => {
if (snapshot.val().data !== undefined) {
const fetchedArray = snapshot.val().data
let array = fetchedArray;
let object = {
"id": `${Math.random()}`,
"images": imagesUriArray,
}
array.push(object)
update(changes, {
data: array
})
}
})
}
}
const uploadImages = () => {
const metadata = {
contentType: 'image/jpeg',
};
pictures.forEach( async (obj) => {
const id = obj.id
const uri = obj.uri
const response = await fetch(uri);
const blob = await response.blob();
var ref = storageUpload(storage, path)
await uploadBytes(ref, blob, metadata)
await getDownloadURL(ref)
.then((metadata) => {
let array = imagesUriArray
let object = {
"id": id,
"uri": metadata
}
array.push(object)
setImageUriArray(array)
})
.catch((error) => {
console.log(error)
});
})
}
return(
..............
)
}
问题
这似乎是 uploadImages
回调中的状态突变。对 imagesUriArray
状态的引用在本地缓存,变异( 即直接推入数组 ),然后将相同的引用保存回状态。这不会触发对任何更新的状态值重新呈现的反应。
const uploadImages = () => {
...
pictures.forEach( async (obj) => {
const id = obj.id
const uri = obj.uri
const response = await fetch(uri);
const blob = await response.blob();
var ref = storageUpload(storage, path)
await uploadBytes(ref, blob, metadata)
await getDownloadURL(ref)
.then((metadata) => {
let array = imagesUriArray // <-- reference to state
let object = {
"id": id,
"uri": metadata
}
array.push(object) // <-- state mutation
setImageUriArray(array) // <-- same state reference
})
.catch((error) => {
console.log(error)
});
})
};
解决方案
使用功能状态更新从以前的状态更新。创建先前状态的浅表副本并附加新数据。
const uploadImages = () => {
...
pictures.forEach( async (obj) => {
const { id, uri } = obj;
const response = await fetch(uri);
const blob = await response.blob();
const ref = storageUpload(storage, path);
await uploadBytes(ref, blob, metadata);
await getDownloadURL(ref)
.then((uri) => {
setImageUriArray(imagesUriArray => [
... imagesUriArray, // <-- shallow copy
{ id, uri }, // <-- append new object
]);
})
.catch(console.log);
})
};
更新
uploadImages
需要 return 一个 Promise,以便 addItem
可以等待它完成其异步代码。 addItem
还需要访问 uploadImages
更新的 imagesUriArray
。
将 pictures
数组映射到最终 return s 具有 id
和新的 uri
属性的对象。
const uploadImages = () => {
...
const fetchImageUri = async ({ id, uri }) => {
try {
const response = await fetch(uri);
const blob = await response.blob();
const ref = storageUpload(storage, path);
await uploadBytes(ref, blob, metadata);
const newUri = await getDownloadURL(ref);
return { id, uri: newUrl };
} catch(error) {
console.log(error);
}
}
return Promise.all(pictures.map(fetchImageUri));
};
更新 addItem
以等待包含已上传图像数据的已解析 Promise 数组。将 imagesUriArray
状态更新排入队列,然后继续引用 uploadImages
.
uploadedImages
数组的其余函数
const addItem = async () => {
const uploadedImages = await uploadImages();
setImageUriArray(imagesUriArray => [
...imagesUriArray, // <-- shallow copy
...uploadedImages, // <-- append new objects
]);
const changes = ref(db, path);
get(changes).then(async (snapshot) => {
if (snapshot.val().data !== undefined) {
const fetchedArray = snapshot.val().data;
const object = {
id: `${Math.random()}`,
images: uploadedImages,
};
update(changes, { data: [...fetchedArray, object] });
}
});
}