Reputation: 1895
I have a simple Navigation link component separated in Container/Presentational classes (Smart/dumb) like so:
My presentational component:
import React, { PropTypes } from 'react';
class Navigation extends React.Component {
componentWillReceiveProps() {
console.log("here bro componentWillReceiveProps");
}
render() {
console.log(this.props);
var self = this;
return (
<div>
<ul>
{
this.props.items.map( (m, index) => {
var style = '';
console.log("index", index, "focus", self.props.focused);
if(self.props.focused == index){
style = 'focused';
}
return <li key={Math.random()} className={style} onClick={self.props.clickHandler.bind(this, index)}>{m}</li>;
})
}
</ul>
<p>Selected: {this.props.items[this.props.focused]}</p>
</div>
);
}
}
export default Navigation;
My container component:
import React, {PropTypes} from 'react';
import Nav from '../components/Navigation';
class NavigationContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
focused : 0
};
}
clicked(index) {
this.setState({focused: index}, function () {
console.log("set to", this.state.focused);
});
}
render() {
return (
<Nav items={['Home', 'About', 'Contact Us']} clickHandler={this.clicked} focused={this.state.focused}/>
);
}
}
NavigationContainer.propTypes = {};
export default NavigationContainer;
When any of the items (home, contact us ...etc) are clicked and state is modified the render() method is not being called again and so the props passed the dumb components are the latest. My understanding is that when state is mutated then render() is called. What am i doing wrong here?
Upvotes: 2
Views: 462
Reputation: 6078
When you extend
React.Component
with ES2015 class syntax you need to bind your action handlers to a context of your class.
Try this:
render() {
return (
<Nav items={['Home', 'About', 'Contact Us']} clickHandler={index => this.clicked(index)} focused={this.state.focused}/>
);
}
Generally, it's better not to use arrow functions or bind
methods inside render
as it generates a new copy of the function on any render
call. Move function declaration to the class constructor
.
I personally prefer to use arrow functions as class properties in this case
class MyClass extends React.Component {
handleClick = () => {
// your logic
};
render() {
return (
<button onClick={this.handleClick}>Click me</button>
);
}
}
It's not a part of ES2015 specification but babel stage-0 preset supports this syntax
You can read more about context binding in React in this article
Upvotes: 4