无法将文件上传到Firebase存储

时间:2019-06-24 18:46:42

标签: javascript reactjs firebase firebase-storage

我正在尝试将文件上传到firebase中,但是文件上传进度达到了100%,然后突然显示了一个未知错误,例如

{
  "error": {
    "code": 400,
    "message": "Bad Request. Could not create object",
    "status": "CREATE_OBJECT"
  }
}

这是我用来上传文件的代码,这是完成文件上传的实际组件,用户打开一个模式以选择文件,然后在选择并按下模式中的send之后,文件上传开始在以下组件中。

import React, { Component } from "react";
import { Segment, Button, Input, ButtonGroup } from "semantic-ui-react";
import firebase from "../../firebase";
import FileModal from "./FileModal";
import uuidv4 from "uuid/v4";

class MessageForm extends Component {
  state = {
    storageRef: firebase.storage().ref(),
    message: "",
    channel: this.props.currentChannel,
    user: this.props.currentUser,
    loading: false,
    errors: [],
    modal: false,
    uploadState: "",
    uploadTask: null,
    percentUploaded: 0
  };

  uploadFile = (file, metadata) => {
    const pathToUpload = this.state.channel.id;
    const ref = this.props.messagesRef;
    const filePath = `chat/public/${uuidv4}.jpg`;

    this.setState(
      {
        uploadState: "uploading",
        uploadTask: this.state.storageRef.child(filePath).put(file, metadata)
      },
      () => {
        this.state.uploadTask.on(
          "state_changed",
          snap => {
            const percentUploaded = Math.round(
              (snap.bytesTransferred / snap.totalBytes) * 100
            );
            this.setState({ percentUploaded });
          },
          err => {
            console.error(err);
            this.setState({
              errors: [...this.state.errors, err],
              uploadState: "error",
              uploadTask: null
            });
          },
          () => {
            console.log(this.state.uploadTask);
            this.state.uploadTask.snapshot.ref
              .getDownloadURL()
              .then(downloadUrl => {
                this.sendFileMessage(downloadUrl, ref, pathToUpload);
              })
              .catch(err => {
                console.error(err);
                this.setState({
                  errors: [...this.state.errors, err],
                  uploadState: "error",
                  uploadTask: null
                });
              });
          }
        );
      }
    );
  };

  sendFileMessage = (fileUrl, ref, pathToUpload) => {
    ref
      .child(pathToUpload)
      .push()
      .set(this.createMessage(fileUrl))
      .then(() => {
        this.setState({
          uploadState: "done"
        }).catch(err => {
          console.error(err);
          this.setState({
            errors: [...this.state.errors, err]
          });
        });
      });
  };

  openModal = () => {
    this.setState({
      modal: true
    });
  };

  closeModal = () => {
    this.setState({
      modal: false
    });
  };

  handleChange = e => {
    this.setState({
      [e.target.name]: e.target.value
    });
  };

  createMessage = (fileUrl = null) => {
    const message = {
      timestamp: firebase.database.ServerValue.TIMESTAMP,
      user: {
        id: this.state.user.uid,
        name: this.state.user.displayName,
        avatar: this.state.user.photoURL
      }
    };
    if (fileUrl != null) {
      message["image"] = fileUrl;
    } else {
      message["content"] = this.state.message.trim();
    }

    return message;
  };

  sendMessage = () => {
    const { messagesRef } = this.props;
    const { message, channel } = this.state;

    if (message) {
      this.setState({
        loading: true
      });
      messagesRef
        .child(channel.id)
        .push()
        .set(this.createMessage())
        .then(() => {
          this.setState({
            loading: false,
            message: "",
            errors: []
          });
        })
        .catch(err => {
          console.error(err);
          this.setState({
            loading: false,
            errors: [...this.state.errors, err]
          });
        });
    } else {
      this.setState({
        errors: [...this.state.errors, { message: "Add a message" }]
      });
    }
  };

  render() {
    const { errors, message, loading, modal } = this.state;
    return (
      <Segment className="message__form">
        <Input
          fluid
          name="message"
          style={{ marginBottom: "0.7em" }}
          icon="add"
          iconPosition="left"
          placeholder="Write your message"
          onChange={this.handleChange}
          className={
            errors.some(error => error.message.includes("message"))
              ? "error"
              : ""
          }
          value={message}
        />
        <ButtonGroup icon widths="2">
          <Button
            onClick={this.sendMessage}
            disabled={loading}
            color="orange"
            content="Add reply"
            labelPosition="left"
            icon="edit"
          />
          <Button
            color="violet"
            content="Upload Media"
            labelPosition="right"
            icon="cloud upload"
            onClick={this.openModal}
          />
          <FileModal
            modal={modal}
            closeModal={this.closeModal}
            uploadFile={this.uploadFile}
          />
        </ButtonGroup>
      </Segment>
    );
  }
}

export default MessageForm;

1 个答案:

答案 0 :(得分:0)

只是个猜测,但我怀疑您的错误可能与将uploadTask存储在组件的state中的方式有​​关...这让我非常不舒服-似乎违反了在React中使用组件状态的核心原则之一。

您可能已经听说过,状态只能通过setState命令进行突变...而您的方法存在的问题是,状态将在执行上传过程中发生变化。实际上,您的代码就依赖它-您已经编写了它,以便在uploadTask更新时,它的百分比就会显示在屏幕上。

总体来说,您有个正确的主意-只需将uploadTask中的uploadTask: this.state.storageRef.child(filePath).put(file, metadata)分派出去……就是这样:

state

未经测试的代码,仅概念性