Reputation: 11030
I'm having trouble understanding why my props.updateBuilding is not working.
The following works when the prop is within the render method
class Buildings extends Component {
constructor(props) {
super(props);
}
componentWillMount() {
this.props.fetchBuildings();
}
renderBuildings(building) {
return (
<div>
<p> {building.name}</p>
</div>
);
}
render() {
return (
<div>
{this.props.buildings.map(this.renderBuildings)}
<button type="button" className="btn btn-success" onClick={this.props.updateBuilding.bind(this, 1)}>Edit</button>
</div>
);
}
}
function mapStateToProps(state) {
return { buildings: state.buildings.all };
}
function mapDispatchToProps(dispatch){
return bindActionCreators({ fetchBuildings, updateBuilding}, dispatch);
}
But when I put this.props.updateBuilding
to the renderBuildings method like below...
renderBuildings(building) {
return (
<div>
<p> {building.name}</p>
<button type="button" className="btn btn-success" onClick={this.props.updateBuilding.bind(this, building.id)}>Edit</button>
</div>
);
}
I get the error:
Cannot read property 'props' of undefined
It seems that the prop updateBuildings
cannot be read when it is inside the renderBuildings method and I'm not sure what is causing this.
Upvotes: 20
Views: 106078
Reputation: 51
I also had some problems using props with my functional components while doing the todo-tutorial. When you use functional components instead of class components, you'll have to do an import from the node-modules if you want to use props. Put this line at the top of your file:
import props from 'prop-types';
Then, when you'll want to use props in your functional component, you'll first need to pass the keyword as a parameter of this function. After that, you'll be allowed to use it like you would have in a class component but without using the keyword "this" :
function Todos(props) {
console.log(props.todos);
return (
<div className="Todos">
<h2>This is the Todos component</h2>
</div>
);
}
Upvotes: 5
Reputation: 21
Binding inline isn't recommended anymore. Now, you can remove the constructor function altogether, and instead of declaring a method on the component, you can declare a property, and set it to an arrow function. This will bind properties to the instance.
Special shoutout to WES BOS for teaching that to me just yesterday in his React for Beginners course! :D Super pumped to actually have something to contribute to Stack Overflow!
renderBuildings = (buildings) => {
//this keyword is now available for use here
}
Upvotes: 2
Reputation: 33974
You are not recommended to bind the function directly in render or anywhere else in the component except in constructor. Because for every function binding a new function/object will be created in webpack bundle js file hence the bundle size will grow. Your component will re-render for many reasons like when you do setState, new props received, when you do this.forceUpdate() etc. So if you directly bind your function in render it will always create a new function. Instead do function binding always in constructor and call the reference wherever required. In this way it creates new function only once because constructor gets called only once per component.
Bind them in constructor and use the reference like
constructor(props){
super(props);
this.renderBuildings = this.renderBuildings.bind(this);
}
this.props.buildings.map(this.renderBuildings)
Upvotes: 1
Reputation: 20528
In my case, I forgot to add props
as an argument to the constructor.
constructor(props) {
super(props);
}
Upvotes: 32
Reputation: 4811
you're miss-reading this error. props
is not undefined, what is calling props
is undefined, which is the this
keyword. you can manually set the context of the map function by passing in a second parameter
this.props.buildings.map(this.renderBuildings, this)
or bind it inline
this.props.buildings.map(this.renderBuildings.bind(this))
Upvotes: 21