15

I am trying to create an app with a CSV upload. When a CSV is uploaded it will change the state and then I will parse from CSV to JSON and do stuff with it. The idea is to upload a file and update state. Once that state is updated I would pass the CSV to a Meteor.method to parse to JSON. I am using Meteor, React and Redux. I have a component that handles the upload, an action and a reducer. All of the files are below - I am new to Meteor, React and Redux and I cannot figure out for the life of me why this is not working. I don't think that I am fully understanding what I am trying to accomplish. Any suggestions are welcome.

ERROR - Uncaught TypeError: fileUpload is not a function UploadCSV.jsx

// ACTIONS - fileUpload.js
export default function fileUpload(file) {
  return {
    type: 'FILE_UPLOAD',
    file
  };
}



//REDUCERS - upLoad.js
export default function upLoad(state = 'NO_FILE', action = {}) {
  switch (action.type) {
    case 'FILE_UPLOAD':
      return action.file;
    default:
      return state;
  }
}



//COMPONENTS - UploadCSV.jsx
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import Dropzone from 'react-dropzone';
import { RaisedButton } from 'material-ui';
import { Colors } from 'material-ui';
import fileUpload from '../actions/fileUpload.js';
import { uploadCSV } from '../actions/uploadCSV.js';

class UploadCSV extends Component {
  render( dispatch, file, fileUpload ) {
    const onDrop = (file) => {
      console.log(file);
    }
    const upLoad = () => {
      this.props.dispatch(fileUpload(file));
    };
    return (
      <div>
        <Dropzone accept="csv"
                  onDrop={ () => {
                      return upLoad();
                    }}>
          <div>Click or drop files here.</div>
        </Dropzone>
      </div>
    )
  }
}

export default connect()(UploadCSV);

I don't understand why fileUpload is "not a function" if it is an action and it is being imported.? If anyone can lend a hand I would appreciate it.

Thanks!

Brandon Baum
  • 155
  • 1
  • 1
  • 6

6 Answers6

28

One reason for this problem that is easy to miss is the following:

If we define the component class with a default export & a named export like this:

// named export
export class MyComponent extends React.Component{      
.......
function mapDispatchToProps(dispatch){
    return bindActionCreators({reduxAction},dispatch)
}
// default export
export default connect(null,mapDispatchToProps)(MyComponent); 

Then we should import the default export not the named export:

This imports the default export & shall work correctly with redux

import MyComponent from "./thePath"

This imports the named export & won't work with redux

import {MyComponent} from "./thePath"

The reason

We have to import the default export when rendering the component in order to use the redux connect() higher order function that we have exported.

Sometimes if you just depend on the editor auto import, it will import the named export (which doesn't have the redux connect) & therefore will give that error

Bottom line

Make sure to import the default export (without braces) when calling the component to use redux connect() correctly

Community
  • 1
  • 1
Ahmed Elkoussy
  • 8,162
  • 10
  • 60
  • 85
  • 2
    Thanks for your comments here, it saved me a big headache. I thought I had not correctly setup my connect function but it was the component import on the parent component. – IronWorkshop Jul 14 '19 at 07:33
4

Restart Your Application

I had the same problem simply because I forgot to restart my application. All the Redux actions are set up at first state, so the Redux Store had no idea that I had implemented a new function.

Hope this helps someone.

Vadim
  • 1,916
  • 2
  • 19
  • 39
2

Because you defined an argument called fileUpload in your render method. Remove all of the arguments you defined in your render method. The class has closure scope over all of those imported modules, so you can reference them anywhere in the class.

Cooper Buckingham
  • 2,503
  • 2
  • 15
  • 23
  • Thanks - that fixed it. I saw an older react/redux example where the reducer functions were being passed into the component, but it was before the current 'render()' syntax. That is where I went wrong. – Brandon Baum Apr 13 '16 at 03:28
2

In case it helps anyone, I received TypeError: this.props.setCategories is not a function until I noticed that the value for setCategories should have been a callback:

const mapDispatchToProps = dispatch => {
    return {
        setCategories: dispatch(actionCreator.setCategories()),  // cause of error
        onAgeUp: () => dispatch(actionCreator.ageUp(1)),
        onAgeDown: () => dispatch(actionCreator.ageDown(1))
    };
};
pjdavis
  • 325
  • 4
  • 25
0

It appears that imported elements are case insensitive when importing them. This is what cause the same issue for me as well, so just a heads up.

William
  • 600
  • 5
  • 14
0

I had this problem when I added new import to bindActionCreators and instead of { } I wrapped it with [ ] so check your brackets

function mapDispatchToProps(dispatch) {
  return bindActionCreators({...UserActions, ...ModalActions}, dispatch)
}
Daniel Kukula
  • 333
  • 3
  • 7