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>
)
}
}
Related
After upgrading to react 16 I am getting null in console.log(this.child)
My parent component
import EditReview from './partials/editReview'
class VenueDetails extends Component {
constructor(props) {
super(props)
this.child = React.createRef();
}
editButtonClick = () => {
console.log(this.child)
this.child.current.onEditClick()
}
render() {
return (
<div>
<button className="pull-right" onClick={() => this.editButtonClick(review, i)}>edit</button>
<div className="place-review-text">
<EditReview {...this.props}/>
</div>
</div>
)
}
}
My child component
class EditReview extends Component {
onEditClick(review, editIndex) {
console.log('ppp')
}
render() {
return ()
}
}
export default EditReview
I need to call onEditClick from the parent component. I tried this but doesn't work.
Kindly help me
You have to assign the ref:
<EditReview {...this.props} ref={this.child} />
Also, you don't need to use inline arrow function:
onClick={() => this.editButtonClick(review, i)}
// ------^^^^^ not required
// because, you're already using public class method
Just use:
onClick={this.editButtonClick(review, i)}
Define your method like this:
editButtonClick = (review, index) => { // to access review, i
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()
I have a little component like this (Code below is simplified to the parts needed) that behaves very strange when it comes to updating the state.
class Componenent extends React.Component {
constructor(props) {
super(props);
this.state = {showStuff: false};
}
render() {
return(
//Markup
{this.state.showStuff && (
<button onClick={() => this.setState({showStuff: false})} />
)}
// More Markup
);
}
}
The state gets updated somewhere else in the component, so the prop is true when the button is clicked.
A click also triggers the setState function (callback gets executed), however the state does not update.
My guess is that it does not update because the function is called by an element that directly depends on the state prop to be visible.
I figured out that adding another prop test: true to the state and changing that property to false when the button is clicked also triggers the showStuff prop to change to false. So it works when I make strange hacks.
Can someone explain this weird behavior to me? I can't gasp why the above snippet does not work like intended.
Here is the entire component:
class ElementAdd extends React.Component {
constructor(props) {
super(props);
this.defaultState = {
showElementWheel: false,
test: true
};
this.state = this.defaultState;
}
handleAddCardClick() {
if (this.props.onCardAdd) {
this.props.onCardAdd({
type: ElementTypes.card,
position: this.props.index
});
}
}
handleAddKnowledgeClick() {
if (this.props.onCardAdd) {
this.props.onCardAdd({
type: ElementTypes.knowledge,
position: this.props.index
});
}
}
handleTabPress(e) {
if (e.key === 'Tab') {
e.preventDefault();
let target = null;
if (e.shiftKey) {
if (e.target.previousSibling) {
target = e.target.previousSibling;
} else {
target = e.target.nextSibling;
}
} else {
if (e.target.nextSibling) {
target = e.target.nextSibling;
} else {
target = e.target.previousSibling;
}
}
target.focus();
}
}
hideElementWheel() {
// This is somehow the only option to trigger the showElementWheel
this.setState({ test: false });
}
render() {
return (
<div
className="element-add"
style={{ opacity: this.props.invisible ? 0 : 1 }}
onClick={() => this.setState(prevSate => ({ showElementWheel: !prevSate.showElementWheel }))}
>
<PlusIcon className="element-add__icon" />
{this.state.showElementWheel && (
<React.Fragment>
<div className="element-add__wheel">
<button
autoFocus
className="element-add__circle"
onClick={this.handleAddCardClick.bind(this)}
onKeyDown={this.handleTabPress.bind(this)}
title="New element"
>
<ViewModuleIcon className="element-add__element-icon" />
</button>
<button
className="element-add__circle"
onClick={this.handleAddKnowledgeClick.bind(this)}
onKeyDown={this.handleTabPress.bind(this)}
title="New knowledge-element"
>
<FileIcon className="element-add__element-icon" />
</button>
</div>
<div
className="element-add__close-layer"
onClick={() => {
this.hideElementWheel();
}}
/>
</React.Fragment>
)}
</div>
);
}
}
By writing onClick={this.setState({showStuff: false})} you are actually calling setState as soon as your button is rendered.
You want to give a function reference to onClick, not call it immediately on render.
<button onClick={() => this.setState({showStuff: false})} />
If your button is inside another element with a click listener that you don't want to run on the same click, you must make sure that the click event doesn't propagate to the parent.
<button
onClick={(event) => {
event.stopPropagation();
this.setState({showStuff: false});
}}
/>
Actually the onClick prop expects a function, you are already providing a function call, so the setState will be called each time the component is rendered, not when clicked.
Try this:
<button onClick={() => this.setState({showStuff: false})} />
Should behave as you expect :)
Works perfectly fine when I update showStuff true (see updated code below.). My guess is the code that is supposed to set showStuff: true is not working. I also added some text in the button.
import React from 'react'
import ReactDOM from 'react-dom'
class Componenent extends React.Component {
constructor(props) {
super(props);
this.state = {showStuff: true};
}
render() {
return(
<div>
{this.state.showStuff && (
<button onClick={() => this.setState({showStuff: false})} > This is a button</button>
)}
</div>
);
}
}
ReactDOM.render(<Componenent />,
document.getElementById('root')
);
Before clicking
After clicking
I am pretty new to react and I have been stuck in a problem for quite a good time.
I have a component DisplayList that iterates through an array of objects and displays them in a list form. Each object becomes a button. I also have another component to render the single view of each item on the list once the item is clicked. My problem is that I get to render the single view of all my items at once INSIDE my displayList component. All I want is to be able to click on the list item and render another component with ONLY info about the item I clicked on and passing my "project" as the props to it. what should I do? What is my error?
My DisplayList component (the part that matters for this problem):
export default class DisplayList extends Component {
constructor() {
super();
this.state = {
displaySingle: false
};
}
handleClick = () => {
this.setState({
displaySingle: true
})
}
render() {
if (this.props.projects && this.props.projects.length > 0) {
return (
<List component="nav">
{this.props.projects.map(project => (
<div className="all-content-wrapper" key={project.id}>
<ListItem button value={project} onClick={this.handleClick}>
{this.state.displaySingle ?
<DisplaySingleItem project={project} /> :
null
}
<ListItemICon>
<img
className="single-item-img-in-list-view"
src={project.img}
/>
</ListItemICon>
You are just a hint away from doing it the right way:
Change the condition in your onClick() as:
onClick={()=>this.handleClick(project.id)}
{ this.state.displayProject_id === project.id ?
<DisplaySingleItem project={project} /> :
null
}
Now define handleClick() as:
handleClick = (project_id) => {
this.setState({
displayProject_id: project_id
})
}
Don't forget to define the initial state in the constructor:
this.state = {
displayProject_id:null
};
<div className="all-content-wrapper" key={project.id}>
<ListItem button value={project} onClick={()=>this.handleClick(project)}>
{this.state.displayProject && this.state.displayProject.id==project.id ?
<DisplaySingleItem project={project} /> :
null
}
<ListItemICon>
<img
className="single-item-img-in-list-view"
src={project.img}
/>
</ListItemICon>
</ListItem>
</div>
change your JSX like the above so you pass the current project to handleClick and change handleClick like the following.
handleClick = (project) => {
this.setState({
displayProject : project
})
}
It should now display the <DisplaySingleItem/> for the clicked project.
For you to be able to show only the project that was selected it is important that you have a reference to it. Right now your handleClick() function does not accept and parameters or data that you can identify the project that was selected.
My solution for you is to pass the project as a parameter to handleClick(project). So your code should look like.
export default class DisplayList extends Component {
constructor() {
super();
this.state = {
displaySingle: false
};
}
handleClick = (project) => {
this.setState({
selectedProject: project, // <- use this state to show your popup or
// whatever view you're using
displaySingle: true
})
}
render() {
if (this.props.projects && this.props.projects.length > 0) {
return (
<List component="nav">
{this.props.projects.map(project => (
<div className="all-content-wrapper" key={project.id}>
<ListItem button value={project} onClick={() => this.handleClick(project)}>
{this.state.displaySingle ?
<DisplaySingleItem project={project} /> :
null
}
<ListItemICon>
<img
className="single-item-img-in-list-view"
src={project.img}
/>
</ListItemICon>
)
}
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)}