React js onClick 无法将值传递给方法
我想读取 onClick 事件值属性。但是当我单击它时,我在控制台上看到类似以下内容:
SyntheticMouseEvent {dispatchConfig: Object, dispatchMarker: ".1.1.0.2.0.0:1", nativeEvent: MouseEvent, type: "click", target
我的代码运行正常。运行时我可以看到
{column},但无法在 onClick 事件中获取它。
我的代码:
var HeaderRows = React.createClass({
handleSort: function(value) {
console.log(value);
},
render: function () {
var that = this;
return(
<tr>
{this.props.defaultColumns.map(function (column) {
return (
<th value={column} onClick={that.handleSort} >{column}</th>
);
})}
{this.props.externalColumns.map(function (column) {
// Multi dimension array - 0 is column name
var externalColumnName = column[0];
return ( <th>{externalColumnName}</th>);
})}
</tr>
);
}
});
如何在 React js 中将值传递给
onClick
事件?
简单方法
使用箭头函数:
return (
<th value={column} onClick={() => this.handleSort(column)}>{column}</th>
);
这将创建一个新函数,该函数使用正确的参数调用
handleSort
。
更好的方法
将其提取到子组件中。 在渲染调用中使用箭头函数的问题是它每次都会创建一个新函数,最终导致不必要的重新渲染。
如果你创建一个子组件,你可以传递处理程序并使用 props 作为参数,然后只有当 props 更改时才会重新渲染(因为处理程序引用现在永远不会变化):
子组件
class TableHeader extends Component {
handleClick = () => {
this.props.onHeaderClick(this.props.value);
}
render() {
return (
<th onClick={this.handleClick}>
{this.props.column}
</th>
);
}
}
主组件
{this.props.defaultColumns.map((column) => (
<TableHeader
value={column}
onHeaderClick={this.handleSort}
/>
))}
旧的简便方法(ES5)
使用
.bind
传递您想要的参数,这样您就可以将函数与组件上下文绑定在一起:
return (
<th value={column} onClick={this.handleSort.bind(this, column)}>{column}</th>
);
这里有很好的答案,我同意@Austin Greco(第二个选项,带有单独的组件)
我喜欢另一种方式,
currying
。
您可以做的是创建一个接受参数(您的参数)的函数并返回另一个接受另一个参数(在本例中为点击事件)的函数。然后你就可以自由地用它做任何你想做的事情了。
ES5:
handleChange(param) { // param is the argument you passed to the function
return function (e) { // e is the event object that returned
};
}
ES6:
handleChange = param => e => {
// param is the argument you passed to the function
// e is the event object that returned
};
你可以这样使用它:
<input
type="text"
onChange={this.handleChange(someParam)}
/>
下面是这种用法的完整示例:
const someArr = ["A", "B", "C", "D"];
class App extends React.Component {
state = {
valueA: "",
valueB: "some initial value",
valueC: "",
valueD: "blah blah"
};
handleChange = param => e => {
const nextValue = e.target.value;
this.setState({ ["value" + param]: nextValue });
};
render() {
return (
<div>
{someArr.map(obj => {
return (
<div>
<label>
{`input ${obj} `}
</label>
<input
type="text"
value={this.state["value" + obj]}
onChange={this.handleChange(obj)}
/>
<br />
<br />
</div>
);
})}
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<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="root"></div>
请注意,这种方法并不能解决每次渲染时创建新实例的问题。
与其他内联处理程序相比,我更喜欢这种方法,因为在我看来,这种方法更简洁、更易读。
编辑:
正如下面的评论所建议的,你可以缓存/记忆函数的结果。
这是一个简单的实现:
let memo = {};
const someArr = ["A", "B", "C", "D"];
class App extends React.Component {
state = {
valueA: "",
valueB: "some initial value",
valueC: "",
valueD: "blah blah"
};
handleChange = param => {
const handler = e => {
const nextValue = e.target.value;
this.setState({ ["value" + param]: nextValue });
}
if (!memo[param]) {
memo[param] = e => handler(e)
}
return memo[param]
};
render() {
return (
<div>
{someArr.map(obj => {
return (
<div key={obj}>
<label>
{`input ${obj} `}
</label>
<input
type="text"
value={this.state["value" + obj]}
onChange={this.handleChange(obj)}
/>
<br />
<br />
</div>
);
})}
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<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="root" />
如今,有了 ES6,我觉得我们可以使用更新的答案。
return (
<th value={column} onClick={()=>this.handleSort(column)} >{column}</th>
);
基本上,(对于任何不知道的人)因为
onClick
期望传递给它一个函数,
bind
可以工作,因为它会创建一个函数的副本。相反,我们可以传递一个箭头函数表达式,它只调用我们想要的函数,并保留
this
。您永远不需要在 React 中绑定
render
方法,但如果出于某种原因您在某个组件方法中丢失了
this
:
constructor(props) {
super(props);
this.myMethod = this.myMethod.bind(this);
}