FirebaseのStorage上では画像が反映されるが、それがCloud Firestore上に反映されず画像が表示できない
解決したいこと
React, Reduxを使い、ECアプリを作成しています。その際にFirebaseのStorage上では画像が保存されるのですが、それがCloud Firestore上だと反映されずビューに画像が表示できない現象を改善したいです。
該当するソースコード
ImageArea.jsx
import React, { useCallback } from "react"
import IconButton from "@material-ui/core/IconButton"
import AddPhotoAlternateIcon from '@material-ui/icons/AddPhotoAlternate';
import { makeStyles } from "@material-ui/styles";
import { storage } from "../../firebase/index"
import ImagePreview from "./ImagePreview"
const useStyles = makeStyles({
icon: {
height: 48,
width: 48
}
})
const ImageArea = (props) => {
const classes = useStyles();
const deleteImage = useCallback(async (id) => {
const ret = window.confirm('この画像を削除しますか?');
if (!ret) {
return false
} else {
const newImages = props.images.filter(image => image.id !== id);
props.setImages(newImages);
return storage.ref('images').child(id).delete()
}
}, [props.images])
const uploadImage = useCallback((event) => {
const file = event.target.files;
let blob = new Blob(file, { type: "image/jpeg" });
// Generate random 16 digits strings
const S = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
const N = 16;
const fileName = Array.from(crypto.getRandomValues(new Uint32Array(N))).map((n) => S[n % S.length]).join('')
const uploadRef = storage.ref('images').child(fileName);
const uploadTask = uploadRef.put(blob);
uploadTask.then(() => {
// Handle successful uploads on complete
uploadTask.snapshot.ref.getDownloadURL().then((downloadURL) => {
const newImage = { id: fileName, path: downloadURL };
props.setImages((prevState => [...prevState, newImage]))
});
});
}, [props.setImages]);
return (
<div>
<div className="p-grid__list-images">
{props.images.length > 0 && (
props.images.map(image => <ImagePreview delete={deleteImage} id={image.id} path={image.path} key={image.id} />)
)}
</div>
<div className="u-text-right">
<span>商品画像を登録する</span>
<IconButton className={classes.icon}>
<label>
<AddPhotoAlternateIcon />
<input className="u-display-none" type="file" id="image"
onChange={(event) => uploadImage(event)}
/>
</label>
</IconButton>
</div>
</div>
)
}
export default ImageArea
operations.js
import { db, FirebaseTimestamp } from "../../firebase"
import { push } from "connected-react-router"
import { fetchProductsAction } from "./actions"
const productsRef = db.collection("products");
export const fetchProducts = () => {
return async (dispatch) => {
productsRef.orderBy("updated_at", "desc").get()
.then(snapshots => {
const productList = []
snapshots.forEach(snapshot => {
const product = snapshot.data();
productList.push(product)
})
dispatch(fetchProductsAction(productList))
})
}
}
export const saveProduct = (id, name, description, category, gender, price, images, sizes) => {
return async (dispatch) => {
const timestamp = FirebaseTimestamp.now();
const data = {
category: category,
description: description,
gender: gender,
images: images,
name: name,
price: parseInt(price, 10),
sizes: sizes,
updated_at: timestamp
}
if (id === "") {
const ref = productsRef.doc();
data.created_at = timestamp;
id = ref.id;
data.id = id;
}
return productsRef.doc(id).set(data, { merge: true })
.then(() => {
dispatch(push("/"))
}).catch((error) => {
throw new Error(error)
})
}
}
ProductEdit.jsx
import React, { useCallback, useEffect, useState } from "react";
import { db } from "../firebase/index";
import { useDispatch } from "react-redux";
import { PrimaryButton, SelectBox, TextInput } from "../components/UIkit";
import { saveProduct } from "../reducks/products/operations";
import { ImageArea, SetSizesArea } from "../components/Products";
const ProductEdit = () => {
const dispatch = useDispatch();
let id = window.location.pathname.split('/product/edit')[1];
if (id !== "") {
id = id.split('/')[1];
}
const genders = [
{ id: "all", name: "すべて" },
{ id: "male", name: "メンズ" },
{ id: "female", name: "レディース" },
];
const [name, setName] = useState(""),
[description, setDescription] = useState(""),
[category, setCategory] = useState(""),
[gender, setGender] = useState(""),
[images, setImages] = useState([]),
[price, setPrice] = useState(""),
[sizes, setSizes] = useState([]);
const inputName = useCallback((event) => {
setName(event.target.value)
}, [setName])
const inputDescription = useCallback((event) => {
setDescription(event.target.value)
}, [setDescription])
const inputPrice = useCallback((event) => {
setPrice(event.target.value)
}, [setPrice]);
const categories = [
{ id: "tops", name: "トップス" },
{ id: "shirts", name: "シャツ" },
{ id: "pants", name: "パンツ" },
];
useEffect(() => {
if (id !== "") {
db.collection("products").doc(id).get().then(snapshot => {
const product = snapshot.data();
setName(product.name);
setDescription(product.description);
setImages(product.images);
setCategory(product.category);
setGender(product.gender);
setPrice(product.price);
setSizes(product.sizes);
})
}
}, [id]);
return (
<section>
<h2 className="u-text__headline u-text-center">
商品の登録・編集
</h2>
<div className="c-section-container">
<ImageArea images={images} setImages={setImages} />
<TextInput
fullWidth={true} label={"商品名"} multiline={false} required={true}
onChange={inputName} rows={1} value={name} type={"text"}
/>
<TextInput
fullWidth={true} label={"商品説明"} multiline={true} required={true}
onChange={inputDescription} rows={5} value={description} type={"text"}
/>
<SelectBox
label={"カテゴリー"} required={true} options={categories} select={setCategory} value={category}
/>
<SelectBox
label={"性別"} required={true} options={genders} select={setGender} value={gender}
/>
<TextInput
fullWidth={true} label={"価格"} multiline={false} required={true}
onChange={inputPrice} rows={1} value={price} type={"number"}
/>
<div className="module-spacer--small" />
<SetSizesArea sizes={sizes} setSizes={setSizes} />
<div className="module-spacer--small" />
<div className="center">
<PrimaryButton
label={"商品情報を保存"}
onClick={() => dispatch(saveProduct(id, name, description, category, gender, price, sizes, images))}
/>
</div>
</div>
</section>
)
}
export default ProductEdit
自分で試したこと
imagesの情報がきちんとFirebase上にデータとして反映されているかという記述漏れがないかは確認しました。また、URLを取得するためのメソッドgetDownloadURL()もImageArea.jsx内に入っております。数日自分で考えたのですが答えがでず、解決法を教えていただけると嬉しいです。何とぞ、よろしくお願い致します。
0