Passing an additional parameter with an onChange event

Viewed 107157

What I'm trying to do:

I am trying to pass a string from a child component to the handleChange function of a parent component.

What currently works:

I have a parent React JS class with the following method:

handleChange(event) {

    console.log(event.target.value);
}

In the render function I have the following:

<Child handleChange={this.handleChange.bind(this)} />

In the Child class I have:

<fieldset onChange={this.props.handleChange}>
    <div>Tag 1: <input id="tag1" value={tags[0]} /></div>
    <div>Tag 2: <input id="tag2" value={tags[1]} /></div>
    <div>Tag 3: <input id="tag3" value={tags[2]} /></div>
</fieldset>

This works fine.

What I am trying to do instead:

I am attempting to add a section parameter to the handleChange function as follows:

handleChange(section, event) {
    console.log(section);
    console.log(event.target.value);
}

And in the Child class I have:

<fieldset onChange={this.props.handleChange("tags")}>
    <div>Tag 1: <input id="tag1" value={tags[0]} /></div>
    <div>Tag 2: <input id="tag2" value={tags[1]} /></div>
    <div>Tag 3: <input id="tag3" value={tags[2]} /></div>
</fieldset>

I now get the error:

Uncaught TypeError: Cannot read property 'target' of undefined

This error is being thrown in my second console.log statement.

What am I doing wrong?

Also, I am considering making the section parameter optional. If so, is there an easy way to do this? It seems like it might not be possible if the event parameter needs to be last.

7 Answers

In your handle event use double arrow function, there's no need to bind when using arrow function:

handleChange = tags => (event) => {
    console.log(tags);
    console.log(event.target.value);
}

And in the Child:

<fieldset onChange={this.props.handleChange("tags")}>
    <div>Tag 1: <input id="tag1" value={tags[0]} /></div>
    <div>Tag 2: <input id="tag2" value={tags[1]} /></div>
    <div>Tag 3: <input id="tag3" value={tags[2]} /></div>
</fieldset>
const handleChange = (tags) => (event) => {
// console.log(tags);
// console.log(event.target.value);
};

<input
      type="text"
      name="name"
      placeholder="Name"
      value={input.Iname}
      onChange={handleChange("Iname")}
    />

No anonymous function defined on each render():

Most of the answers here recommend an anonymous function defined in render(), which, as Davidicus pointed out, is not recommended: https://medium.freecodecamp.org/why-arrow-functions-and-bind-in-reacts-render-are-problematic-f1c08b060e36

François's answer avoids that problem, but as Vael Victus pointed out, that requires transform-class-properties.

However, what he's doing is just defining a function which defines a function, which you can otherwise do like this:

constructor(props) {
  super(props);
  this.handleChange = (yourSpecialParam) => (event) => this.handleChange(yourSpecialParam).bind(this)
}

render() {
  return <button onClick={this.handleChange(1234)} >Click Me</button>
}
Related