LiamG_G
LiamG_G

Reputation: 129

React: How to render same component with same onClick and different drops

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

Answers (5)

Murat Karag&#246;z
Murat Karag&#246;z

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

Ivan Mjartan
Ivan Mjartan

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

Shubham Jain
Shubham Jain

Reputation: 930

Inside of your constructor bind this to the function as

this.handleClick = this.handleClick.bind(this);

Upvotes: 0

Dev
Dev

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

An Nguyen
An Nguyen

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

Related Questions