Unable to call function from onClick in React - javascript

I have a render within a component that looks like this:
render() {
if (!this.props.authorities) {
return <div>Loading...</div>
}
return (
<div>
<Col xsOffset={0.5} md={2}>
<ButtonGroup Col xsOffset={1} md={4} justified centered>
<DropdownButton title="Authority" id="bg-justified-dropdown">
{this.props.authorities.map(this.renderAuthority)}
</DropdownButton>
</ButtonGroup>
</Col>
</div>
)
}
}
It renders a list of dropdown items using the renderAuthority function, which looks like this:
renderAuthority(authorityData) {
return (
<MenuItem onClick={this.clickAuthority(authorityData.LocalAuthorityId)} key={authorityData.LocalAuthorityId} eventKey={authorityData.LocalAuthorityId}>{authorityData.Name}</MenuItem>
)
}
The onClick within there calls a function called clickAuthority, which looks like this:
clickAuthority(data) {
this.props.fetchRatings(data)
}
My constructor also looks like this:
constructor(props) {
super(props);
this.clickAuthority = this.clickAuthority.bind(this);
}
However, I get an error with the following:
Unhandled Rejection (TypeError): Cannot read property 'clickAuthority' of undefined
This references the MenuItem onClick. Any idea what I'm doing wrong and how I might fix it?

By default, the .map() function bind the callback with global environnement object. So binds your this.renderAuthority function with this in your constructor too.
constructor(props) {
super(props);
this.renderAuthority = this.renderAuthority.bind(this);
this.clickAuthority = this.clickAuthority.bind(this);
}
Secondly, when you are writing that:
onClick={this.clickAuthority(authorityData.LocalAuthorityId)}
You are instantly calling the function and giving its return to the onClick property. You have to make this:
onClick={() => this.clickAuthority(authorityData.LocalAuthorityId)}

Related

Calling function in react native outside component

My requirement
I am calling my function placed outside of the component and view in react native, but it throws errors saying the _this.myfunction is undefined. Its clearly not getting the reference for the function. Is it possible to achieve such feature in react native.
class App extends React.Component {
constructor(props) {
super(props);
}
render () {
return (
<View style={styles.container}>
<Button onPress={() => this.Myfunction()} style={styles.Button} title="Button"/>
</View>
);
}
}
Myfunction () {
alert('clicked');
}
Since you've defined the function outside of the class, you don't need to refer it by this. You can simply write onPress={() => Myfunction()} or onPress={Myfunction}
Also your function's syntax is wrong, add the function keyword before it
function Myfunction () {
alert('clicked');
}

React state component - Cannot read property 'state' of undefined

I have the following problem - I can't read value from my state, I get the error:
Cannot read property 'state' of undefined
My class component with a state:
class SideNav extends Component {
state = {
brand: 'Thule'
}
handleToggle = () => this.setState({open: !this.state.open});
handleBrand = (evt) => {
this.setState({brand: evt.target.value});
console.log(this.state.brand); --> WORKS HERE!!!
}
searchProducts() {
console.log(this.state.brand); --> ERROR: cannot read 'state' property of undefined
}
render() {
return (
<div className={classes.sideNav}>
<Button variant={"outlined"} onClick={this.handleToggle} className={classes.sideNavBtn}>Search</Button>
<Drawer
className={classes.drawer}
containerStyle={{top: 55}}
docked={false}
width={200}
open={this.state.open}
onRequestChange={open => this.setState({open})}
>
<AppBar title="Search"/>
<form noValidate autoComplete="off" onSubmit={this.searchProducts}>
<TextField
id="brand"
label="Brand"
margin="normal"
onChange={this.handleBrand}
/>
<Button variant="contained" color="primary" onClick={this.searchProducts}>
Search
</Button>
</form>
</Drawer>
</div>
);
}
}
export default SideNav;
I wonder WHY I'm able to read my this.state.bran value in:
handleBrand = (evt) => {
this.setState({brand: evt.target.value});
console.log(this.state.brand);
}
but NOT in
searchProducts() {
console.log(this.state.brand);
}
I don't understand this case.
searchProducts is a class method either bind it in constructor or use arrow functions (like in handleBrand). Currently your accessing the wrong value for this
searchProducts = () =>{}
Using bind
constructor(){
this.searchProducts = this.searchProducts.bind(this)
}
Arrow functions have lexical this. By using this inside a class method you are accessing the local scope of searchProducts not the Component's instance
this works in confusing ways in JavaScript. It's not working as intended in searchProduct() because you're passing it as a prop to a child component. In your constructor you should bind it to the instance like this:
constructor(props) {
super(props);
this.searchProducts = this.searchProducts.bind(this);
}

React - Can't get function to fire from child props

I am trying to get this function to fire from on click call in a child component.
getTotalOfItems = () => {
console.log('anything at all?')
if (this.props.cart === undefined || this.props.cart.length == 0) {
return 0
} else {
const items = this.props.cart
var totalPrice = items.reduce(function (accumulator, item) {
return accumulator + item.price;
}, 0);
this.setState({
estimatedTotal: totalPrice
});
};
}
This on click is being fired from within a Cart component
<button onClick={() => {props.addToCart(item); props.getPrice.bind(this)} }>+</button>
The cart component is being added to the ItemDetails component here
export default class ItemDetails extends Component {
constructor(props) {
super(props);
this.state = {
open: false
};
}
render() {
return(
<div>
<Button
className="item-details-button"
bsStyle="link"
onClick={() => this.setState({open: !this.state.open})}
>
{this.state.open === false ? `See` : `Hide`} item details
{this.state.open === false ? ` +` : ` -`}
</Button>
<Collapse in={this.state.open}>
<Cart
getPrice={this.props.getPrice}
/>
</Collapse>
</div>
)
}
}
Finally the ItemDetails component is added into the app.js like so
render() {
return (
<div className="container">
<Col md={9} className="items">
<ProductListing products={this.props.initialitems} />
</Col>
<Col md={3} className="purchase-card">
<SubTotal price={this.state.total.toFixed(2)} />
<hr />
<EstimatedTotal
price={this.state.estimatedTotal.toFixed(2)} />
<ItemDetails
price={this.state.estimatedTotal.toFixed(2)}
getPrice={ () => this.getTotalOfItems() }
/>
<hr />
<PromoCodeDiscount
giveDiscount={ () => this.giveDiscountHandler() }
isDisabled={this.state.disablePromoButton}
/>
</Col>
</div>
);
};
If I remove the () = > before the this.getTotalOfItems() it fires the function on the onClick, however it causes an infinite loop of re-rendering out the app causing an error.
Is there anyway to fix this? I am a novice at React and this is one of my first projects using it. Any advice shall be appreciated.
Sorry if this isn't explained to well, I am happy to provide any additional information if required.
Thanks!
You have to trigger getPrice method, now all you do is binding this context. Instead of props.getPrice.bind(this) you should have: props.getPrice()
props.getPrice.bind(this) doesn't call the function it just binds 'this' to it.
You should use props.getPrice() instead, also you don't have to bind the context of a children to it.
Some additionnal tips/explanations :
You can rewrite all your functions calls like this one :
getPrice={ () => this.getTotalOfItems() }
to
getPrice={this.getTotalOfItems}
It will pass the function to the child instead of creating a function which trigger the function (same result, better performance)
But if you do this :
getPrice={this.getTotalOfItems()}
It'll trigger the function at each render(), causing an infinite loop if the function triggers a render() itself by calling this.setState()

React how to invoke a prop

I'm trying to invoke a method on the component props before the page load. For testing I've created a button to invoke the method , but this is not what I desire , and I don't know how to change it so it will be called instantly when you reach this path .
My current code :
class BrokersList extends React.Component {
getTableData = () => {
this.props.getBrokerDetails()
}
render () {
return (
<Paper className={this.props.classes.root}>
<button
variant="outlined"
color="primary"
onClick={this.getTableData}></button>
{this.props.details.length > 0 && <Table {...this.props}/>}
</Paper>
)
}
}
I thought about calling the getTableData via the render method, but render should be pure so it didn't work . (Table component is being populated from the state that is being updated by this method)
For this you can use the componentDidMount life cycle method.
Here is example code of what may work for you.
class BrokersList extends React.Component {
componentDidMount() {
this.props.getBrokerDetails()
}
render () {
return (
<Paper className={this.props.classes.root}>
{this.props.details.length > 0 && <Table {...this.props}/>}
</Paper>
)
}
}
Now your call to getBrokerDetails will fire right after the first render of this component. See here for more details on this life cycle method.
If you pass method to handler as is that use this it will be window object or undefined if used in strict mode:
class BrokersList extends React.Component {
getTableData = () => {
this.props.getBrokerDetails()
}
render () {
return (
<Paper className={this.props.classes.root}>
<button
variant="outlined"
color="primary"
onClick={() => this.getTableData()}></button>
{this.props.details.length > 0 && <Table {...this.props}/>}
</Paper>
)
}
}
or using onClick={this.getTableData.bind(this)}
What's wrong with this?
class BrokersList extends React.Component {
render () {
// get method props
const {getBrokerDetails} = this.props
return (
<Paper className={this.props.classes.root}>
<button
variant="outlined"
color="primary"
onClick={getBrokerDetails}></button>
{/* call the method ^^ */}
{this.props.details.length > 0 && <Table {...this.props}/>}
</Paper>
)
}
}

Call function onPress React Native

I just want to know how to call a function onPress. I've setup my code like this:
export default class Tab3 extends Component {
constructor(props) {
super(props);
this.state = {myColor: "green"};
}
handleClick = () => {
if (this.state.color === 'green'){
this.setState({myColor: 'blue'});
} else {
this.setState({myColor: 'green'});
}
}
render() {
return(
<View>
<Icon
name='heart'
color={this.state.myColor}
size= {45}
style={{marginLeft:40}}
onPress={() => handleClick(this)}
/>
</View>
)};
But when I try this, I'm getting error that can't find variable handleClick
Please help. I just want to know how to bind a function to a click event.
In you're render you're setting up the handler incorrectly, give this a try;
<View>
<Icon
name='heart'
color={this.state.myColor}
size= {45}
style={{marginLeft:40}}
onPress={this.handleClick}
/>
</View>
The syntax you're using would make sense for declaring an anonymous function inline or something but since your handler is defined on the class, you just reference it (not call it) using this.functionName in the props.
A little late to the party, but just wanted to leave this here if someone needs it
export default class mainScreen extends Component {
handleClick = () => {
//some code
}
render() {
return(
<View>
<Button
name='someButton'
onPress={() => {
this.handleClick(); //usual call like vanilla javascript, but uses this operator
}}
/>
</View>
)};
You need to reference the method with the this keyword.
<Icon
onPress={this.handleClick}
/>
you can also try this way of binding
this.handleClick = this.handleClick.bind(this)
and put this inside constructor. And while calling use this syntax
onPress = {this.handleClick}
This will surely solve your problem.
If you are not using class components, you can just drop the this
This function can handle the navigation for any route (as long as there is one screen with the name passed as the argument) removing the need for multiple handlers.
const navigation = useNavigation();
function handleNavigation(route) {
navigation.navigate(route);
}
and the button will look like this:
<Button onPress={() => handleNavigation("Menu")} ></Button>

Categories

Resources