10

I am receiving this error: this.props.postBooks is not a function.

I have an action - postBooks - which I am trying to dispatch via props.

Here is my component:

"use strict"

import React from 'react'
import {Well,Panel,FormControl,FormGroup,ControlLabel,Button} from 'react-bootstrap'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import {postBooks} from '../../actions/booksActions'
import {findDOMNode} from 'react-dom'

export class BooksForm extends React.Component{

    handleSubmit(){
        const book = [{
            title: findDOMNode(this.refs.title).value,
            description: findDOMNode(this.refs.description).value,
            price: findDOMNode(this.refs.price).value
        }]
        this.props.postBooks(book)
    }
    render(){

        return(
            <Well>
                <Panel>
                    <FormGroup    controlId='title'>
                        <ControlLabel> Title </ControlLabel>
                        <FormControl    
                            type='text'
                            placeholder='Enter Title'
                            ref='title' />
                    </FormGroup>

                    <FormGroup    controlId='description'>
                        <ControlLabel> Enter Description </ControlLabel>
                        <FormControl    
                            type='text'
                            placeholder='Enter Description'
                            ref='description' />
                    </FormGroup>

                    <FormGroup    controlId='price'>
                        <ControlLabel> Enter Price </ControlLabel>
                        <FormControl    
                            type='text'
                            placeholder='Enter Price'
                            ref='price' />
                    </FormGroup>
                    <Button 
                    onClick={this.handleSubmit.bind(this)}
                    bsStyle='primary'> Enter New Book </Button>

                </Panel>
            </Well>
            )
    }

}

function mapDispatchToProps(dispatch){
    return bindActionCreators({postBooks},dispatch)
}
export default connect(null,mapDispatchToProps)(BooksForm);

It seems that dispatch is not being mapped to props as expected since upon console logging props, props are empty. Any help appreciated. Thanks in advance

Edit: Added Actions

 "use strict"
// POST A BOOK
export function postBooks(book){
    return {
        type:"POST_BOOK",
        payload: book
    }
}
// DELETE A BOOK
export function deleteBooks(id){
    return {
        type:"DELETE_BOOK",
        payload: id
    }
}
//UPDATE BOOK
export function updateBooks(book){
    return {
        type:"UPDATE_BOOK",
        payload: book
    }
}

//Retrieve all books as if using API

export function getBooks(){
    return{
        type:'GET_BOOKS'
    }
}
Ahmed Elkoussy
  • 8,162
  • 10
  • 60
  • 85
bbmhmmad
  • 372
  • 1
  • 6
  • 21

5 Answers5

16

Figured it out.

So I was exporting component up top and export default below.

Noticed webpack was giving an error 'import and export may only appear at top level'. Went ahead and removed top export and now works as expected.

bbmhmmad
  • 372
  • 1
  • 6
  • 21
  • 6
    I'm glad it's working for you now, but I don't think that was actually your issue. the difference between `export class BooksForm ...` and `export default connect` is one is imported in another file using `import { BooksForm } from './BooksForm'` and the other is `import BooksForm from './BooksForm'` (notice the brackets). The way you were exporting was fine, and is often done that way for testing purposes. The webpack error is [more likely related to an error in your babel config](https://stackoverflow.com/questions/37902849/import-and-export-may-only-appear-at-the-top-level). – Michael Peyper Jul 02 '17 at 11:39
  • I aslo removed my export from Class line and rebuilt my project, react native. Works now. Thanka. – Hesam Nov 18 '17 at 23:18
  • 1
    The reason I made this same mistake was that I went from an existing exported regular component to connecting the component to redux. – icc97 Apr 26 '19 at 08:23
  • This was also my problem. Good pick up. – micnguyen Aug 14 '19 at 04:52
12

Faced the same issue and I just removed the curly braces from import:

From import {AppTest} from "./AppTest"; To import AppTest from "./AppTest";

And that seemed to fixed the issue. Note that I had "export default" in my class already.

Nate
  • 10,361
  • 3
  • 33
  • 40
mezzie
  • 1,276
  • 8
  • 14
8

So I had this same issue & the problem was the same as shown in the other useful answers but I will try to explain why this happens in more details

If we define the class with a default export & a named export as shown here (based on the question):

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

Then we have to be careful when importing the class to import the default export not the named export:

This imports the default export & shall work correctly with redux

import BooksForm from "./thePath"

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

import { BooksForm } from "./thePath"

If we define the two imports in the same class (which is usually done to make unit testing easier) :

Then 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 autoimport, it will import the named export (which doesn't have the redux connect) & therefore will give that error

Bottom line

You don't have to remove any of the 2 exports, just import the default export (without braces) to use redux connect() correctly

Community
  • 1
  • 1
Ahmed Elkoussy
  • 8,162
  • 10
  • 60
  • 85
1

I faced the same issue once, and I found that importing two files into each other causes some kind of infinite loop and it just breaks the process. I was using flow static type checker, and while I was importing my action into my component, I imported my component into my action file for a type checking, and this issue occured, so I removed importing my component to my action file, and the problem solved.

masoud
  • 116
  • 1
  • 1
  • 10
0

Please try again after importing the redux store. Let me know if that worked or not.And also using refs is not recommended. https://facebook.github.io/react/docs/refs-and-the-dom.html

Phanindra
  • 1
  • 2
  • Take the curly braces around postBooks inside the bindActionCreators. The action creator should be a function, you gave it an object. I guess that's the problem. Let me know. – Phanindra Jul 02 '17 at 02:54
  • I dont think so. By using object as so I am letting bindActionCreators know that postBooks prop in this component should dispatch the postBooks action that I have imported from my bookActions module. I have used this format before with no problems. – bbmhmmad Jul 02 '17 at 03:56