React+Next.js+firebaseで画像アップローダを作った

このサイト参考にアップロードサイト作成中
How to do image upload with firebase in react.

ただ、firebaseの認証等は、「react.js&next.js超入門 第2版」を参考に、 components/fire.jsに保存

//App.js
// このサイト参考にアップロードサイト作成中
// https://dev.to/itnext/how-to-do-image-upload-with-firebase-in-react-cpj
// いったん開発の間はstorageのルールの認証を切る
// いちいちログインするの時間がかかり非効率

// firebase公式ドキュメントも参考にする
// https://firebase.google.com/docs/storage/web/start?hl=ja

//またreact.js&next.js超入門 第2版も参考にした
//https://www.shuwasystem.co.jp/book/9784798063980.html

import { useState } from "react"
import firebase from "firebase"

import Layout from "../../components/layout"
import "../../components/fire"

const auth = firebase.auth();
const provider = new firebase.auth.GoogleAuthProvider();
const storage= firebase.storage()

auth.signOut()

export default function Index() {
  const [user,setUser]=useState(null);
  const [message, setMessage] = useState('please login ...');

  // ログイン処理
  const login = () =>{
    console.log("login")
    auth.signInWithPopup(provider).then(
      result=>{
        setUser(result.user.displayName);
        setMessage('logined: '+result.user.displayName);
      },
      error=>{
        setUser('NONE');
        setMessage('not logined.')
      }
    )
  }

  // ログアウト処理
  const logout = () => {
    auth.signOut();
    setUser(null);
    setMessage('logout...')
  }

  // ログイン表示をクリックしたとき
  const doLogin = (e) => {
    if (auth.currentUser == null){
      login();
    } else {
      logout();
    }
  }

  return (
    <div>
      <Layout header="Next.js" title="Top page.">
      <div className="alert alert-primary text-center">
        <h6 className="text-right" onClick={doLogin}>LOGINED: {user}</h6>
        <h5 className="mb-4">{message}</h5>
      </div>
      <Upload />
      </Layout>
    </div>
  )
}

function Upload() {
  console.log("Upload 呼び出し")
  const allInputs = {imgUrl: ''}
  const [imageAsFile, setImageAsFile] = useState('')
  const [imageAsUrl, setImageAsUrl] = useState(allInputs)

  console.log(imageAsUrl)
  const handleImageAsFile = (e) => {
    const image = e.target.files[0]
    setImageAsFile(imageFile => (image))
  }

  const handleFireBaseUpload = e => {
    e.preventDefault()
    console.log('start of upload')
    // async magic goes here...
    if(imageAsFile === '' ||  imageAsFile === undefined) {
      console.error(`not an image, the image file is a ${typeof(imageAsFile)}`)
    } else {
      const uploadTask = storage.ref(`/images/${imageAsFile.name}`).put(imageAsFile)
      //initiates the firebase side uploading 
      //https://firebase.google.com/docs/storage/web/upload-files?hl=ja#monitor_upload_progress
      //このドキュメントだけ呼んだだけだと分かりにくいが、
      //uploadTask.onの第1引数に'state_changed'を指定すると
      //第2、第3、第4引数に渡した関数で
      // アップロード状況を管理することができる。
      uploadTask.on('state_changed', 
      (snapShot) => {
        //takes a snap shot of the process as it is happening
        console.log(snapShot)
      }, (err) => {
        //catches the errors
        console.log(err)
      }, () => {
        // gets the functions from storage refences the image storage in firebase by the children
        // gets the download url then sets the image from firebase as the value for the imgUrl key:
        storage.ref('images').child(imageAsFile.name).getDownloadURL()
        .then(fireBaseUrl => {
          //オブジェクトのスプレッド構文による展開と、値の更新
          //{imgUrl: 古いURL}を{imgUrl: 新しいURL}に更新している。
          //https://qiita.com/FumioNonaka/items/58358a29850afd7a0f37
          setImageAsUrl(prevObject => ({...prevObject, imgUrl: fireBaseUrl}))
        })
      })
    }
  }

  return <div>
    <form className="form-group" onSubmit={handleFireBaseUpload}>
    <input className="form-control-file mb-1"
        // allows you to reach into your file directory and upload image to the browser
          type="file"
          onChange={handleImageAsFile}
        />
    <button className="btn btn-primary">アップロード</button>
    </form>
    <img src={imageAsUrl.imgUrl} alt="image tag" />
    </div>
}