Trouble with passing a function as prop in react?

Maybe I’m tired, but I’m not seeing any reason why this onSelectionChange is not working!???

This is my first file (a list of cards):

import React from 'react';
import { Button, Row, Col, Card } from 'antd';
import { VendorCard } from '../common'


export class VendorList extends React.Component {
	constructor(props){
		super(props);
		this.onSelectionChange = this.onSelectionChange.bind(this);
		this.state = {
			compareVendorIds: [],
		}
	}
	onSelectionChange(value, vendorId){
		console.log(value);
		console.log(vendorId);
		if (value) {
			let currentState = this.state.compareVendorIds;
			currentState.push(vendorId)
			this.setState({compareVendorIds: currentState});
		}
		
	}
	render( ){
		const {vendors} = this.props;
		return (
			<Row>
			
			{vendors.map((vendor)=>{
				return (
					<Col key={vendor._id} span='8'>
						<VendorCard 
                                                       item={vendor} compareSelection={this.onSelectionChange} 
                                                />
					</Col>
				);
			})}
			</Row>
		);
	}
}


And this is the card that is receiving this.onSelectionChange


import React from 'react';
import { Button, Row, Col, Card, message, Checkbox } from 'antd';



const FeatureCard_Top = ({item, compareSelection}) => {
	return (
		<Row style={{height: 250}}>
			<Checkbox onChange={ (value)=> compareSelection(value.target.checked, item._id) } />
			<h1>{item.title}</h1>
		</Row>
	);
}




class VendorCard extends React.Component {
	constructor(props){
		super(props);
	}
	render(){
		const { item, compareSelection } = this.props;
		return (
			<Card>
				<FeatureCard_Top 
					item={item} 
					compareSelection={(value, vendorId)=>compareSelection(value, vendorId)} 
				/>
			</Card>
		);
	}
}



export { VendorCard };

Maybe with this ?

render( ){
                const _this = this;
		const {vendors} = this.props;
		return (
			<Row>
			
			{vendors.map((vendor)=>{
				return (
					<Col key={vendor._id} span='8'>
						<VendorCard 
                                                       item={vendor} compareSelection={_this.onSelectionChange} 
                                                />
					</Col>
				);
			})}
			</Row>
		);
	}

(I add the _this constant)

It is strange because this is receiving the correct data from the the card component… but if I pass this.onSelectChange as a prop it is not registered as a function. I feel like I do this all the time with no trouble so I’m really confused. I’ll give your _this strategy a try but why is that needed?

render( ){
		const {vendors} = this.props;
		return (
			<Row>
			
			{vendors.map((vendor)=>{
				return (
					<Col key={vendor._id} span='8'>
						<VendorCard 
                                                     item={vendor} 
                                                    compareSelection={(value, vendorId)=>console.log(value, vendorId)} />
					</Col>
				);
			})}
			</Row>
		);
	}

This worked, but I’m confused why. I guess it is one of the “this” confusion problems everyone complains about. I have never run into this before.

Yeah, the this problem is very confusing :wink:

I always make a constant of this to avoid that.
I can’t explain the right way why this append, but I think that :

When you are in the map function, this don’t reference the component but the actual iterator I think.
So when you want to put this in a nested component, try with _this :wink:

(I know it’s not the good answer !)

From StackOverflow :

Array.prototype.map() takes a second argument to set what this refers to in the mapping function, so pass this as the second argument to preserve the current context:

someList.map(function(item) {

}, this)
Alternatively, you can use an ES6 arrow function to automatically preserve the current this context:

someList.map((item) => {

})

1 Like

Ok, here a best answer :smile: