使用 onChange 事件传递附加参数

我想做的是:

我尝试将一个字符串从子组件传递给父组件的 handleChange 函数。

目前的工作方式:

我有一个父 React JS 类,其方法如下:

handleChange(event) {


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

在渲染函数中,我有以下内容:

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

在儿童课上,我有:

<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>

这样挺好的。

相反,我正在努力做的是:

我试图向 handleChange 函数添加一个 section参数,如下所示:

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

在孩子课上,我有:

<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>

我现在明白了错误所在:

Uncaught TypeError: Cannot read property 'target' of undefined

这个错误将在我的第二个 console.log 语句中引发。

我做错了什么?

此外,我正在考虑使 section参数成为可选的。如果是这样,有没有简单的方法可以做到这一点?如果事件参数必须是最后一个,那么似乎不太可能。

111851 次浏览

When you are writing this:

<fieldset onChange={this.props.handleChange("tags")}>

handleChange will be called immediately as soon as render is triggered.

Instead, do it like this:

<fieldset onChange={(e) => this.props.handleChange("tags", e)}>

Now the handleChange will be called when onChange handler is called.

You can do this:

<fieldset onChange={(e) => this.props.handleChange("tags", e)}>
<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>

In order to pass a param from the child component to the parent you can take an argument to the arrow function.

handleChange(event, section) {
console.log(section);
console.log(event.target.value);
}
<Child handleChange={(e, val) => this.handleChange(e, val)} />


<fieldset onChange={(e) => this.props.handleChange(e, "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>

Sample snippet

class App extends React.Component {
handleChange(e, val) {
console.log(e.target.value, val);
}
render() {
return(
<Child handleChange={(e,val) => this.handleChange(e, val)}/>
)
}
}


class Child extends React.Component {
  

render() {
return(
<input type="text" onChange={(e) => this.props.handleChange(e, 'tab')}/>
)
}
}


ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

As the OP, I had originally posted this as a follow up on my question, but it was deleted and I was told to post it as an answer instead, so here it is:

Based on Ritesh Bansal's answer, I have learned the following:

The following line was not working because when using parenthesis after the function name, the function is called immediately rather than waiting for a change to happen:

<fieldset onChange={this.props.handleChange("tags")}>

The above will not work, neither would a function such as this:

<fieldset onChange={this.props.handleChange()}>

The above would also get called immediately on first render.

There are two solutions to this:

The not-so good way:

<fieldset onChange={this.props.handleChange.bind(this, "tags")}>

The much better way:

<fieldset onChange={(evt) => this.props.handleChange("tags", evt)}>

The problem is now solved. Thank you everyone!

Update:

I also researched Shubham Khatri's suggestion to change the child element to this:

<Child handleChange={(e,val) => this.handleChange(e, val)}/>

I did not realize that using bind in the render function, that every time render is called it creates a new function instance. I can, therefore, either use Shubham Khatri's method, or bind the methods in the constructor.

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>

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>
}
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")}
/>