1

Short explanation of use case: I need to allow the user to include multiple files in a single form, but from different folders (the different folders requirement means I can't simply use the "multiple" attribute.) I'm not allowed to assign File objects to <input> fields dynamically (source), which means I need to wait until the user chooses a single file, then I need to capture that node (with the file), hide it, and create a new input node in its place.

I have a proof of concept which works with jQuery but I'm trying to figure out how to do this the Redux way. My proposed solution is as follows:

  • When the user uploads a file, I dispatch an action which should insert the input DOM node into an array in state and also hide() it.
  • Dynamically create a new input node in the exact same place that the first one was
  • In another location on the page, display the filenames from the input nodes currently in state
  • These filename displays will also have a delete button which would dispatch a delete action which would delete the corresponding node in state.
  • When the user submits the form it should include all the file nodes that have been added, and therefore all the files will be submitted at once.

My first question: Is it going to be possible to do this? In particular, can I store a node in state?

My second question: I've not sure how to get a reference to the node to even test this.

Finally, Once I add the node into state and hide() it, how do I go about creating a new <input> node in its place? As I said, this is easy using jQuery but I'm interested in how to do it the "redux" way

Here's some code I have

Component - Uploader.js

import React, { Component } from 'react';

class Uploader extends Component {

  renderHiddenInputs(files){
    if(!this.props.files || this.props.files.length == 0) {
      return
    }
    return files.map((file) => {
      return (
        <li>
        <h3>{file}</h3> // return file node
        </li>
      )
    });

  }

  renderFileNames(files){
    if(!this.props.files || this.props.files.length == 0) {
      return <h3>There are no files</h3>
    }
    return files.map((file) => {
      return (
        <li>
        <h3>{file.files[0].name}</h3> //return filenames only
        </li>
      )
    });

  }

  render() {

    return (
      <div>
        <div><input type="file" id="fileinput" onChange={this.props.addInput}/></div> //How do I pass in a ref to this exact node so It can be store in state and then create a new one in it's place?
        <hr />
        <div>{this.renderHiddenInputs(this.props.files)}</div> //we need the input nodes on the page so when the form submits the files get sent
        <div>
        <ul>
        {this.renderFileNames(this.props.files)} //the input nodes are hidden so here we display the filenames for the user to see
        </ul>
        </div>
      </div>
    );
  }
}

Container - UploaderContainer.js

import { connect } from 'react-redux'
import { uploadFile, addInput } from '../actions/index';

import Uploader from '../components/Uploader';


const mapStateToProps = (state) => {
  return {
    files: state.files
  };
}

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
        addInput: (inputNode) => { //How do I get inputNode?
          dispatch(addInput(inputNode))
        }
  }
}


const UploaderContainer = connect(mapStateToProps, mapDispatchToProps)(Uploader)

export default UploaderContainer
Community
  • 1
  • 1
asolberg
  • 6,638
  • 9
  • 33
  • 46

0 Answers0