2
votes

I have a CRUD React app where you can create articles. There is a 'title', 'content' and 'image'.

I have a collection in Cloud Firestore called 'articles'. The documents have the fields: 'title' and 'content' so every time I create an article in my react app, a new document is created.

The next step was to be able to add images to the articles.

I managed to connect to Firebase and upload an image to Firebase Storage from my React page. However how do I connect the images to their articles? Like, how do I make the connection between Cloud Firestore and Storage?

Do I create an extra field in my documents called 'images'? But then how do I reference it? I also want to try and avoid duplicates.

UploadImage.js


import React, { useState, Component } from "react";
import { storage } from "../Firebase";

function UploadFile() {
        const [image, setImage] = useState(null);
        const [url, setUrl] = useState("");
        const [progress, setProgress] = useState(0);

        const handleChange = e => {
            if (e.target.files[0]) {
              setImage(e.target.files[0]);
            }
          };

          const handleUpload = () => {
            const uploadTask = storage.ref(`images/${image.name}`).put(image);
            uploadTask.on(
              "state_changed",
              snapshot => {
                const progress = Math.round(
                  (snapshot.bytesTransferred / snapshot.totalBytes) * 100
                );
                setProgress(progress);
              },
              error => {
                console.log(error);
              },
              () => {
                storage
                  .ref("images")
                  .child(image.name)
                  .getDownloadURL()
                  .then(url => {
                    setUrl(url);
                  });
              }
            );
          };

          console.log("image: ", image);

      return (
        <div>
      <progress value={progress} max="100" />
      <br />
      <br />
      <input type="file" onChange={handleChange} />
      <button onClick={handleUpload}>Upload</button>
      <br />
      {url}
      <br />
      <img src={url || "http://via.placeholder.com/300"} alt="firebase-image" />
    </div>
         
      );
    }

    export default UploadFile;

This is my 'Add Article' form-->

AddArticle.js

import React, { Component } from 'react';
import firebase from '../Firebase';
import UploadFile from '../components/UploadFile';

class AddArticle extends Component {

  constructor() {
    super();
    this.ref = firebase.firestore().collection('articles');
    this.state = {
      title: '',
      content: ''
    };
  }
  onChange = (e) => {
    const state = this.state
    state[e.target.name] = e.target.value;
    this.setState(state);
  }

  onSubmit = (e) => {
    e.preventDefault();

    const { title, content } = this.state;

    this.ref.add({
      title,
      content

    }).then((docRef) => {
      this.setState({
        title: '',
        content: ''
      });
      this.props.history.push("/")
    })
    .catch((error) => {
      console.error("Error adding document: ", error);
    });
  }

  render() {
    const { title, content } = this.state;
    return (
      <div className="container">
      <br></br><br></br><br></br>
        <div className="panel panel-default">
          <div className="panel-heading">
            <h3 className="panel-title text-center">
              Create a new article
            </h3>
          </div>
          <br></br><br></br>
          <div className="panel-body">
            <form onSubmit={this.onSubmit}>
              <div className="form-group">
                <label for="title">Title:</label>
                <input type="text" className="form-control" name="title" value={title} onChange={this.onChange} placeholder="Title" />
              </div>
              <div className="form-group">
                <label for="content">Content:</label>
                <textArea className="form-control" name="content" onChange={this.onChange} placeholder="Content" cols="80" rows="20">{content}</textArea>
              </div>
              <UploadFile />
              <button type="submit" className="btn btn-success">Submit</button>
            </form>
          </div>
        </div>
      </div>
    );
  }
}

export default AddArticle;
1
Yes, you can use a field in the document to store references to images in Cloud Storage. Your question is unclear about what you're stuck on with respect to that. Please edit the question to narrow the focus on a single question that explain where you are stuck. Right now you are asking too many questions at once.Doug Stevenson
@DougStevenson I just don't know what I need to add to my code to make that connection. If I add the extra field, what do I need to do in my code in order to associate the actual image to the document? I'm fairly new too this, most of my code is from tutorials I found online.cldev
It depends on what specifically you're trying to do. Just write the path of the file in storage to the document so that when you read the document later, you can rebuild a reference to the file.Doug Stevenson

1 Answers

2
votes

It is actually pretty simple, to achieve this follow steps below:

  1. After uploading your image to firebase storage you should get download url for that particular image (I linked firebase documentation link below on how to achieve that).

https://firebase.google.com/docs/storage/web/download-files

  1. If you successfully fetched download url from firebase storage now it is time to create separate field under your document named such as "postImageUrl" (you can name whatever you want) and save download url under this field.

  2. Now you can show images using this download url in your page using busboy library

https://www.npmjs.com/package/busboy

Note: I am an Android Developer so I tried my best to help. If you have further questions don't hesitate to ask