codyc4321 codyc4321 - 3 years ago 102
Javascript Question

Pass state updater clickHandler in React

I have a React app like:

Main.js-

import React, { Component } from 'react';
import _ from 'underscore';

import ApplicationsButtons from '../components/ApplicationsButtons';


let applications_url = 'http://127.0.0.1:8889/api/applications'


export default class Main extends Component {

constructor(props) {
super(props);
this.state = {applications: [], selected_app: 1};
this.updateSelectedApp = this.updateSelectedApp.bind(this);
}

componentDidMount() {
let self = this;
$.ajax({
url: applications_url,
method: 'GET',
success: function(data) {
console.log(data);
let objects = data.objects;
let apps = objects.map(function(object) {
return {name: object.name, id: object.id};
});
console.log(apps);
self.setState({applications: apps});
}
});
}

updateSelectedApp(id) {
this.setState({selected_app: id});
}

render() {

return (
<div>
{this.state.selected_app}
<ApplicationsButtons apps={this.state.applications} />
</div>
);
}
}


ApplicationsButtons.js-

import React, { Component } from 'react';


export default class ApplicationsButtons extends Component {

render() {
var buttons = null;
let apps = this.props.apps;
let clickHandler = this.props.clickHandler;
if (apps.length > 0) {
buttons = apps.map(function(app) {
return (<button key={app.id}>{app.name} - {app.id}</button>);
// return (<button onClick={clickHandler.apply(null, app.id)} key={app.id}>{app.name} - {app.id}</button>);
});
}

return (
<div>
{buttons}
</div>
);
}
}


I want to pass an onClick to the buttons that will change the currently selected app. Somehow, I just got my first infinite loop in React ("setState has just ran 20000 times"). Apparently, when I tried to pass the event handler to be called on click, I told it to keep calling it.

The onClick function should change
state.selected_app
for the
Main
component, based on the
id
for the button that was clicked.

Answer Source

You are not passing the handler as prop. Here's what you should do:

render() {
  return (
    <div>
      {this.state.selected_app}
      <ApplicationsButtons 
         apps={this.state.applications} 
         handleClick={this.updateSelectedApp}
      />
    </div>
  );
}

And in ApplicationButtons:

render() {
  var buttons = null;
  let apps = this.props.apps;
  let clickHandler = this.props.handleClick;
  if (apps.length > 0) {
    buttons = apps.map(app => 
      <button key={app.id} onClick={() => clickHandler(app.id)}>{app.name} - {app.id}</button>);
    );
  }

  return (
    <div>
      {buttons}
    </div>
  );
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download