tylermcginnis / re-base

:fire: A Relay inspired library for building React.js + Firebase applications. :fire:
2.13k stars 143 forks source link

syncState preventing File upload? #266

Open dwijesingheWR opened 5 years ago

dwijesingheWR commented 5 years ago

Hi,

My React app allows the user to select one or more images, renders a preview of the selected images, then allows them to submit the image up to the server. Until they are sent to the server, images are store in the App state as an associative array {files: []}. The code was working until I started using Firebase to persist the App state and added a syncState call for files. After adding the syncState call my addFile function can no longer update the App state files array. I tested, and simply removing the syncState code for files restores full functionality to the app. Am I doing something wrong in terms of how I'm using syncState here? I have another syncState call on separate App data and it works without issue.

This is the code from my FileSelector component:

class FileSelector extends React.Component {
  handleFileSelection = event => {
    this.props.addFile(event.target.files[0]);
  };

  render() {
    return (
      <div className="input-group mb-3">
        <div className="custom-file">
          <input
            type="file"
            accept=".jpg,.png,.gif,.mp4"
            className="custom-file-input"
            id="inputGroupFile02"
            onChange={this.handleFileSelection}
          />
          <label className="custom-file-label">
            {Object.keys(this.props.files).length === 0
              ? "Choose file"
              : Object.keys(this.props.files)[
                  Object.keys(this.props.files).length - 1
                ]}
          </label>
        </div>
      </div>
    );
  }
}

And the code for addFile (coded in a parent component and passed via props)

  addFile = file => {
    const files = { ...this.state.files };
    //files[file.name] = file;
    let filenameNoDot = file.name;
    filenameNoDot = filenameNoDot.replace(".", "_");
    console.log("File: " + filenameNoDot);
    files[filenameNoDot] = file;
    console.log(JSON.stringify(files));
    this.setState({ files });
  };

Finally my componentDidMount method which has the syncState code

  componentDidMount() {
    this.ref = base.syncState(`${this.props.draftName}/data`, {
      context: this,
      asArray: false,
      state: "data",
      defaultValue: {
        title: "Your message title should go here",
        text: "Your text should go here"
      }
    });

    this.fileRef = base.syncState(`${this.props.draftName}/files`, {
      context: this,
      asArray: true,
      state: "files"
    });
qwales1 commented 5 years ago

@dwijesingheWR doing files[filenameNoDot] = file; is not iterable by the normal javascript array methods . For instancefiles.map or files.forEach would produce an empty array which is my guess why it wipes it out completely. try asArray : false

dwijesingheWR commented 5 years ago

@qwales1 Thanks for getting back to me. I tried setting asArray to both true and false, I've also tried changing files to an object instead of an array, neither seems to be helping. Without syncState, either an object or an array works fine, with syncState added, setState simply will not update files (although checking in the debugger, I can see that the files array created in addFile updates appropriately). Any thoughts on why this might be?

qwales1 commented 5 years ago

@dwijesingheWR is the database getting updated at all?

dwijesingheWR commented 5 years ago

Yes I have another syncState call watching a different state property (data) and all changes to data, which is a fairly simple object, persist to Firebase without issue. In addition if I change

files[filenameNoDot] = file;

to

files[filenameNoDot] = 42;

the files array gets updated in Firebase. It seems to be a specific issue with File objects.

qwales1 commented 5 years ago

@dwijesingheWR oh yeah now i see that sorry. I'm not sure about storing files in firebase directly. base64 encoding them looks like it works from a quick search but I know they have Firebase Storage now for files