Home > Net >  Checkbox onchange function is always undefined in React component class
Checkbox onchange function is always undefined in React component class

Time:12-24

My onchange function on my checkbox is always undefined. I made a sandbox to simplify my issue. I've tried changing it back and forth between an arrow and a regular function, and leaving the binding as its default state vs tying it to its binding in the constructor.

import "./styles.css";
import React, { Component } from "react";

class App extends Component {
  constructor(props) {
    super(props);

    this.renderCheckboxes = this.renderCheckboxes.bind(this);
    this.checkboxChange = this.checkboxChange.bind(this);
  }

  checkboxChange = (event) => {
    console.log("CHANGED");
  }

  renderCheckboxes(checkboxes) {
    return checkboxes.map(function (obj, idx) {
      return (
        <div>
          <label>{obj.name}</label>
          <input type="checkbox" onChange={this.checkboxChange} />
        </div>
      );
    });
  }

  render() {
    const cbList = [
      { name: "A", mood: "Happy" },
      { name: "B", mood: "Sad" },
      { name: "C", mood: "Mad" }
    ];

    return <>{this.renderCheckboxes(cbList)}</>;
  }
}

export default App;

My Sandbox

CodePudding user response:

Your function is undefined because you are losing your context when your checkboxes.map happens.

  renderCheckboxes(checkboxes) {
    return checkboxes.map(function (obj, idx) { // here
      return (
        <div>
          <label>{obj.name}</label>
          <input type="checkbox" onChange={this.checkboxChange} />
        </div>
      );
    });
  }

You can change the function for an arrow function, so you won't lose context:

  renderCheckboxes(checkboxes) {
    return checkboxes.map((obj, idx) => { // here
      return (
        <div>
          <label>{obj.name}</label>
          <input type="checkbox" onChange={this.checkboxChange} />
        </div>
      );
    });
  }

It might not be the case, but if you need to send some parameter on your checkboxChange call, you could use it like this:

  checkboxChange = (value) => { // need to set the variable here
    console.log(value);
  }

  renderCheckboxes(checkboxes) {
    return checkboxes.map((obj, idx) => {
      return (
        <div>
          <label>{obj.name}</label>
          <input type="checkbox" onChange={() => this.checkboxChange('test')} />  <!-- so you can pass it from here -->
        </div>
      );
    });
  }

CodePudding user response:

Easy fix, it's because the binding doesn't work within the map function like you have now. To see this in action, try just rendering one checkbox, without map and you'll see your checkbox change method work.

Two changes I suggest:

  1. Change map method to an arrow function:
return checkboxes.map((obj, idx) => {
    ...
}
  1. Change onChange to an arrow function:
onChange={() => this.checkboxChange()}
  • Related