Reputation: 129
I'm trying to use React Components to render all the projects I have in a .json. This is my code so far:
class App extends Component {
constructor(props){
super(props);
this.state = {
load: '',
projectInfo:{
"projects":[]
}
}
}
getProjectInfo(){
$.ajax({
url:'http://localhost:3000/projectInfo.json',
dataType:'json',
cache: false,
success: function(data){
this.setState({projectInfo: data});
}.bind(this),
error: function(xhr, status, err){
console.log(err);
alert(err);
}
});
}
componentDidMount(){
this.getProjectInfo();
}
handleClick = (value) => {
this.setState({load: value});
}
display(app){
if(app == 'bmi') {
return <Bmi />
}
if (app === 'js') {
return <Js />
}
else return "";
}
render() {
if(this.state.projectInfo){
var projects = this.state.projectInfo.projects.map(function(project){
return (<Project id={project.id}
projectName={project.name}
projectDescription={project.description}
imgAddress={project.imgAddress}
onClick={this.handleClick}/>)
})
}
return (
<div className="App">
<div className="App-header">
<h2>React Test</h2>
</div>
<div className="box">
{projects}
</div>
<div className={this.state.load}>
{this.display(this.state.load)}
</div>
</div>
);
}
}
export default App;
I'm having trouble with the onClick, getting the TypeError: Cannot read property 'handleClick' of undefined. I think the problem is that when I use {this.handleClick}, 'this' refers to 'project' passed to the function, but I'm not sure how to get around it.
This was working as desired when I manually listed all the Project Components to be rendered.
Upvotes: 0
Views: 3254
Reputation: 37584
You did not bind the map for the context of this
, but since you are using () =>
notation you can make use of the auto bind e.g.
var projects = this.state.projectInfo.projects.map(project => {
return (<Project id={project.id}
projectName={project.name}
projectDescription={project.description}
imgAddress={project.imgAddress}
onClick={this.handleClick}/>)
})
EDIT:
To pass more arguments you have to use a callback for onClick
e.g.
onClick={() => this.handleClick(project.id)}
Upvotes: 1
Reputation: 987
Hi you have problem with context. My suggestion is create proper function to handle click
handleClick(value){
this.setState({load: value});
}
than add lambda function to:
if(this.state.projectInfo){
var projects = this.state.projectInfo.projects.map((project) => {
return (<Project id={project.id}
projectName={project.name}
projectDescription={project.description}
imgAddress={project.imgAddress}
onClick={()=>{this.handleClick(project.id);}}/>)
})
}
I am not sure what kind of parameter you need to pass to handle click function but i guess that this is project.id
Upvotes: 0
Reputation: 930
Inside of your constructor bind this to the function as
this.handleClick = this.handleClick.bind(this);
Upvotes: 0
Reputation: 3932
You need to bind to the correct context.Either you can do this
onClick={this.handleClick.bind(this)}
OR
In constructor
constructor(props){
super(props);
this.state = {
load: '',
projectInfo:{
"projects":[]
}
};
this.handleClick = this.handleClick.bind(this);
}
Upvotes: 0
Reputation: 1478
Save this.handleClick
to a variable before jump into map
if(this.state.projectInfo){
var handle = this.handleClick
var projects = this.state.projectInfo.projects.map(function(project){
return (<Project id={project.id}
projectName={project.name}
projectDescription={project.description}
imgAddress={project.imgAddress}
onClick={handle}/>)
})
}
Upvotes: 0