4

Normally When i click on the menu item in the child component it calls {this.handlesort} which is a local function. Handle sort takes in onReorder props from my parent component. {onReorder} calls a local function called reOrder. It sets the state of {orderBy and orderDir}. The problem is that immediately when i click on {menuitem} it returns this error. (Uncaught TypeError: Cannot read property 'onReOrder' of undefined). Normally it works when i am not using es6. Please help

(Parent Component)

export default class TenantView extends Component {
    constructor(props) {
        super(props);
        //setting state
        this.state = {
            //tenants: [],
            orderBy: 'name',
            orderDir: 'asc',};
    };
    componentWillMount() {
        this.setState({
            tenants:[{img: 'tenant1.jpg',name: 'John', address: '7 Gilbert', 
                     paid: 'true'},{img: 'tenant2.jpg',name:'Abba', address: 
                     '3 Vecq st', }]});//setState
    }//componentWillMount



    reOrder(orderBy, orderDir) {
        this.setState({
            orderBy: orderBy,
            orderDir: orderDir,
        });//setState
    }//reorder

    render(){
        var tenants = this.state.tenants;
        var orderBy = this.state.orderBy;
        var orderDir = this.state.orderDir;

        tenants = _.orderBy(tenants, function(item) {
            return item[orderBy].toLowerCase();
        }, orderDir);//orderBy

        tenants = tenants.map(function(item, index){
            return (
                <TenantList key = { index } singleTenant = { item } />
             )
        }.bind(this))

        return(
            <div style={styles.root}>
                <Subheader>Payment Status</Subheader>

                <PaymentStatus/>
                <SearchTenant
                    orderBy = { this.state.orderBy }
                    orderDir = { this.state.orderDir }
                    onReOrder = { this.reOrder }
                />
                <GridList cols={1} cellHeight={80} style={styles.gridList}>
                    {tenants}
                </GridList>
            </div>

        )//return
    }//render
}

childcomponent

export default class SearchTenant extends Component {
    handleSort(e){
        this.props.onReOrder(e.target.id, this.props.orderDir)
    }//handleSort

    handleOrder(e){
        this.props.onReOrder(this.props.orderBy, e.target.id)
    }//handleSort


    render(){
       return(
           <div className="input-group">
               <input placeholder="Search" type="text" onChange = { 
                this.handleSearch }  className= "validate"/>
               <DropDownMenu openImmediately={true}>
                   <MenuItem id = "name" onClick = {this.handleSort}>Name{ ( 
                        this.props.orderBy === 'name') ? <i 
                        className="material-icons">check_circle</i>: null }
                   </MenuItem>
                   <MenuItem id = "address" onClick = 
                       {this.handleSort}>Address{ 
                       (this.props.orderBy === 'address') ? <i 
                       className="material-
                       icons">check_circle</i>: null }
                   </MenuItem>
                   <MenuItem id = "asc" onClick = {this.handleOrder}>Asc{ 
                       (this.props.orderDir === 'asc') ? <i 
                       className="material-icons">check_circle</i>: null }
                   </MenuItem>
                   <MenuItem id = "desc" onClick = {this.handleOrder}>Desc{ 
                       (this.props.orderDir === 'desc') ? <i 
                        className="material-icons">check_circle</i>: null }
                   </MenuItem>
               </DropDownMenu>
           </div>
       )//return
    }//render
}//TeamList
Muhammad Ismail
  • 43
  • 1
  • 1
  • 3

2 Answers2

5

You have to ensure that you are binding the functions you pass to inline event handlers properly in order for the calls inside them to be able to reference this of the component scope correctly:

Define the following constructor in your component:

constructor (props){
  super (props):
  this.handleSort = this.handleSort.bind(this);
  this.handleOrder = this.handleOrder.bind(this);
}
Pineda
  • 7,435
  • 3
  • 30
  • 45
4

The problem is that the this you are referring to inside handleSort and handleOrder is not referring to component's this instead it is referring to the internal methods this.

There a re two solutions for this problem.

Either bind the function with component's this inside the component's constructor:

export default class SearchTenant extends Component {

    constructor() {
        this.handleSort = this.handleSort.bind(this)
        this.handleOrder = this.handleOrder.bind(this)
    }

    // rest of the code
}

Or use ES6's arrow function which provides lexical scoping:

export default class SearchTenant extends Component {

    handleSort = () => {
        this.props.onReOrder(e.target.id, this.props.orderDir)
    }
}
Swapnil
  • 2,573
  • 19
  • 30