我想阅读 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
的新函数。
更好的方法
Extract it into a sub-component. 在渲染调用中使用箭头函数的问题在于,它每次都会创建一个新函数,最终导致不必要的重新渲染。
如果你创建一个子组件,你可以传递 handler 并使用 props 作为参数,然后只有当 props 改变时才会重新渲染(因为 handler 引用现在永远不会改变):
子组件
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"];类 App 扩展 React.Component { state = { valueA: "", valueB: "一些初始值", valueC: "", valueD: "blah blah" }; handleChange = 参数 => e => { const nextValue = e.target.value; this.setState({ ["value" + param]: nextValue }); }; render() { return (
请注意,这种方法不能解决在每次渲染时创建新实例的问题。与其他内联处理程序相比,我更喜欢这种方法,因为我认为这种方法更简洁易读。
编辑:正如下面评论中所建议的,您可以缓存/记忆函数的结果。
这是一个幼稚的实现:
让备忘录 = {}; const someArr = ["A", "B", "C", "D"];类 App 扩展 React.Component { state = { valueA: "", valueB: "一些初始值", 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 (
handleChange = param => cache[param] || (e => { // the function body })
如今,有了 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);
}
render()
,因为它是由 React 调用的。如果有的话,您需要 bind
事件处理程序,并且仅当您不使用箭头时。
props
传递给 super()
,否则 this.props
将在构造函数期间未定义,这可能会让人感到困惑。
[[h/t 给 @E.Sundin 的 linking this 在评论中]
最佳答案(匿名函数或绑定)将起作用,但它不是性能最高的,因为它为 map()
函数生成的每个实例创建事件处理程序的副本。
这是对 ESLint-plugin-react 的最佳方法的解释:
项目列表 渲染中绑定的一个常见用例是在渲染列表时,为每个列表项设置一个单独的回调:
const List = props => (
<ul>
{props.items.map(item =>
<li key={item.id} onClick={() => console.log(item.id)}>
...
</li>
)}
</ul>
);
与其这样做,不如将重复的部分拉到它自己的组件中:
const List = props => (
<ul>
{props.items.map(item =>
<ListItem
key={item.id}
item={item}
onItemClick={props.onItemClick} // assume this is passed down to List
/>
)}
</ul>
);
const ListItem = props => {
const _onClick = () => {
console.log(props.item.id);
}
return (
<li onClick={_onClick}>
...
</li>
);
});
这将加快渲染速度,因为它避免了在每次渲染时创建新函数(通过绑定调用)的需要。
this.state
,您可以安全地将其换成 SFC。
这是我的方法,不知道它有多糟糕,请评论
在可点击元素中
return (
<th value={column} onClick={that.handleSort} data-column={column}> {column}</th>
);
接着
handleSort(e){
this.sortOn(e.currentTarget.getAttribute('data-column'));
}
encodeURIComponent(JSON.stringify(myObj))
,然后解析它,JSON.parse(decodeURIComponent(myObj))
。对于函数,我很确定如果没有 eval 或 new Function(),这将无法工作,这两者都应该避免。由于这些原因,我不使用数据属性在 React/JS 中传递数据。
这个例子可能和你的有点不同。但我可以向您保证,这是您可以解决此问题的最佳解决方案。我已经寻找了几天没有性能问题的解决方案。最后想出了这个。
class HtmlComponent extends React.Component {
constructor() {
super();
this.state={
name:'MrRehman',
};
this.handleClick= this.handleClick.bind(this);
}
handleClick(event) {
const { param } = e.target.dataset;
console.log(param);
//do what you want to do with the parameter
}
render() {
return (
<div>
<h3 data-param="value what you wanted to pass" onClick={this.handleClick}>
{this.state.name}
</h3>
</div>
);
}
}
更新
如果您想处理应该是参数的对象。您可以使用 JSON.stringify(object)
将其转换为字符串并添加到数据集中。
return (
<div>
<h3 data-param={JSON.stringify({name:'me'})} onClick={this.handleClick}>
{this.state.name}
</h3>
</div>
);
React Hooks 解决方案 2022
const arr = [
{ id: 1, txt: 'One' },
{ id: 2, txt: 'Two' },
{ id: 3, txt: 'Three' },
]
const App = () => {
const handleClick = useCallback(
(id) => () => {
console.log("ID: ", id)
},
[],
)
return (
<div>
{arr.map((item) => (
<button onClick={handleClick(item.id)}>{item.txt}</button>
))}
</div>
)
}
您可以将一个函数传递给 useCallback 的返回,然后您可以通过将参数传递给它来在渲染中正常调用您的函数。奇迹般有效!只需确保正确设置了 useCallback 的依赖数组即可。
React >= 16 的最佳解决方案
我发现在 onClick、onChange 等中调用具有多个参数的函数而不使用内联函数的最简洁方法是使用 React 16 及更高版本中可用的自定义 data
属性。
const App = () => {
const onClick = (e) => {
const value1 = e.currentTarget.getAttribute("data-value1")
const value2 = e.currentTarget.getAttribute("data-value2")
const value2 = e.currentTarget.getAttribute("data-value2")
console.log("Values1", value1)
console.log("Values2", value2)
console.log("Values3", value3)
}
return (
<button onClick={onClick} data-value1="a" data-value2="b" data-value3="c" />
)
}
上面的示例是针对功能组件的,但即使在类组件中,实现也非常相似。
这种方法不会产生不必要的重新呈现,因为您没有使用内联函数,并且您避免了与 this
绑定的麻烦。
它允许您传递想要在函数中使用的任意数量的值。
如果您将值作为道具传递给您的子组件以在子组件的 onClick 中使用,您也可以在那里使用这种方法,而无需创建包装函数。
如果您想将 id 从对象传递到 onClick
,也适用于对象数组,如下所示。
const App = () => {
const [arrState, setArrState] = useState(arr)
const deleteContent = (e) => {
const id = e.currentTarget.getAttribute("data-id")
const tempArr = [...arrState]
const filteredArr = tempArr.filter((item) => item.id !== id)
setArrState(filteredArr)
}
return (
<div>
{arrState.map((item) => (
<React.Fragment key={item.id}>
<p>{item.content}</p>
<button onClick={deleteContent} data-id={item.id}>
Delete
</button>
</React.Fragment>
))}
</div>
)
}
data-
评论。如此干净和简单
useEffect
无济于事,因为 useCallback
返回的回调仍会在每次渲染时创建新函数。
只需创建一个这样的函数
function methodName(params) {
//the thing you wanna do
}
并在你需要的地方调用它
<Icon onClick = {() => { methodName(theParamsYouwantToPass);} }/>
class extends React.Component {
onClickDiv = (column) => {
// do stuff
}
render() {
return <div onClick={() => this.onClickDiv('123')} />
}
}
我意识到这对聚会来说已经很晚了,但我认为一个更简单的解决方案可以满足许多用例:
handleEdit(event) {
let value = event.target.value;
}
...
<button
value={post.id}
onClick={this.handleEdit} >Edit</button>
我想您也可以使用 data-
属性。
简单,语义。
交替尝试回答 OP 的问题,包括 e.preventDefault() 调用:
渲染链接 (ES6)
<a href="#link" onClick={(e) => this.handleSort(e, 'myParam')}>
组件功能
handleSort = (e, param) => {
e.preventDefault();
console.log('Sorting by: ' + param)
}
不涉及 .bind
或 ES6 的另一种选择是使用带有处理程序的子组件来调用具有必要道具的父处理程序。这是一个示例(下面是工作示例的链接):
var HeaderRows = React.createClass({
handleSort: function(value) {
console.log(value);
},
render: function () {
var that = this;
return(
<tr>
{this.props.defaultColumns.map(function (column) {
return (
<TableHeader value={column} onClick={that.handleSort} >
{column}
</TableHeader>
);
})}
{this.props.externalColumns.map(function (column) {
// Multi dimension array - 0 is column name
var externalColumnName = column[0];
return ( <th>{externalColumnName}</th>
);
})}
</tr>);
)
}
});
// A child component to pass the props back to the parent handler
var TableHeader = React.createClass({
propTypes: {
value: React.PropTypes.string,
onClick: React.PropTypes.func
},
render: function () {
return (
<th value={this.props.value} onClick={this._handleClick}
{this.props.children}
</th>
)
},
_handleClick: function () {
if (this.props.onClick) {
this.props.onClick(this.props.value);
}
}
});
基本思想是父组件将 onClick
函数传递给子组件。子组件调用 onClick
函数并可以访问传递给它的任何 props
(和 event
),从而允许您在父 onClick
函数中使用任何 event
值或其他道具。
下面的 CodePen demo 显示了此方法的实际效果。
如果您使用 ES6
,您可以简单地执行此操作。
export default class Container extends Component {
state = {
data: [
// ...
]
}
handleItemChange = (e, data) => {
// here the data is available
// ....
}
render () {
return (
<div>
{
this.state.data.map((item, index) => (
<div key={index}>
<Input onChange={(event) => this.handItemChange(event,
item)} value={item.value}/>
</div>
))
}
</div>
);
}
}
通过将计数作为参数从主组件传递到子组件来实现显示对象的总计数,如下所述。
这是 MainComponent.js
import React, { Component } from "react";
import SubComp from "./subcomponent";
class App extends Component {
getTotalCount = (count) => {
this.setState({
total: this.state.total + count
})
};
state = {
total: 0
};
render() {
const someData = [
{ name: "one", count: 200 },
{ name: "two", count: 100 },
{ name: "three", count: 50 }
];
return (
<div className="App">
{someData.map((nameAndCount, i) => {
return (
<SubComp
getTotal={this.getTotalCount}
name={nameAndCount.name}
count={nameAndCount.count}
key={i}
/>
);
})}
<h1>Total Count: {this.state.total}</h1>
</div>
);
}
}
export default App;
这是SubComp.js
import React, { Component } from 'react';
export default class SubComp extends Component {
calculateTotal = () =>{
this.props.getTotal(this.props.count);
}
render() {
return (
<div>
<p onClick={this.calculateTotal}> Name: {this.props.name} || Count: {this.props.count}</p>
</div>
)
}
};
尝试在上面实现,您将获得传递参数如何在任何 DOM 方法上的 reactjs 中工作的确切场景。
有几种方法可以在事件处理程序中传递参数,下面是一些。
您可以使用箭头函数环绕事件处理程序并传递参数:
<button onClick={() => this.handleClick(id)} />
上面的例子等价于调用 .bind
或者你可以显式调用 bind。
<button onClick={this.handleClick.bind(this, id)} />
除了这两种方法之外,您还可以将参数传递给定义为 curry 函数的函数。
handleClick = (id) => () => {
console.log("Hello, your ticket number is", id)
};
<button onClick={this.handleClick(id)} />
我写了一个包装器组件,可以在此目的上重复使用,它建立在此处接受的答案的基础上。但是,如果您需要做的只是传递一个字符串,那么只需添加一个数据属性并从 e.target.dataset 中读取它(就像其他一些人建议的那样)。默认情况下,我的包装器将绑定到任何作为函数并以“on”开头的道具,并在所有其他事件参数之后自动将数据道具传递回调用者。虽然我没有测试过它的性能,但它会让你有机会避免自己创建类,它可以像这样使用:
const DataButton = withData('button')
const DataInput = withData('input');
或用于组件和功能
const DataInput = withData(SomeComponent);
或者如果你喜欢
const DataButton = withData(<button/>)
声明在您的容器外(靠近您的进口)
这是容器中的用法:
import withData from './withData';
const DataInput = withData('input');
export default class Container extends Component {
state = {
data: [
// ...
]
}
handleItemChange = (e, data) => {
// here the data is available
// ....
}
render () {
return (
<div>
{
this.state.data.map((item, index) => (
<div key={index}>
<DataInput data={item} onChange={this.handleItemChange} value={item.value}/>
</div>
))
}
</div>
);
}
}
这是包装代码'withData.js:
import React, { Component } from 'react';
const defaultOptions = {
events: undefined,
}
export default (Target, options) => {
Target = React.isValidElement(Target) ? Target.type : Target;
options = { ...defaultOptions, ...options }
class WithData extends Component {
constructor(props, context){
super(props, context);
this.handlers = getHandlers(options.events, this);
}
render() {
const { data, children, ...props } = this.props;
return <Target {...props} {...this.handlers} >{children}</Target>;
}
static displayName = `withData(${Target.displayName || Target.name || 'Component'})`
}
return WithData;
}
function getHandlers(events, thisContext) {
if(!events)
events = Object.keys(thisContext.props).filter(prop => prop.startsWith('on') && typeof thisContext.props[prop] === 'function')
else if (typeof events === 'string')
events = [events];
return events.reduce((result, eventType) => {
result[eventType] = (...args) => thisContext.props[eventType](...args, thisContext.props.data);
return result;
}, {});
}
我对 JSX onClick 事件有以下 3 条建议-
实际上,我们不需要在代码中使用 .bind() 或 Arrow 函数。您可以在代码中简单使用。您还可以将 onClick 事件从 th(或 ul)移动到 tr(或 li)以提高性能。基本上,您的 n li 元素将有 n 个“事件侦听器”。所以最后代码看起来像这样:
我以两种方式添加了用于将 onclick 事件值传递给方法的代码。 1.使用绑定方法 2. 使用箭头(=>)方法。请参阅方法 handlesort1 和 handlesort
var HeaderRows = React.createClass({
getInitialState : function() {
return ({
defaultColumns : ["col1","col2","col2","col3","col4","col5" ],
externalColumns : ["ecol1","ecol2","ecol2","ecol3","ecol4","ecol5" ],
})
},
handleSort: function(column,that) {
console.log(column);
alert(""+JSON.stringify(column));
},
handleSort1: function(column) {
console.log(column);
alert(""+JSON.stringify(column));
},
render: function () {
var that = this;
return(
<div>
<div>Using bind method</div>
{this.state.defaultColumns.map(function (column) {
return (
<div value={column} style={{height : '40' }}onClick={that.handleSort.bind(that,column)} >{column}</div>
);
})}
<div>Using Arrow method</div>
{this.state.defaultColumns.map(function (column) {
return (
<div value={column} style={{height : 40}} onClick={() => that.handleSort1(column)} >{column}</div>
);
})}
{this.state.externalColumns.map(function (column) {
// Multi dimension array - 0 is column name
var externalColumnName = column;
return (<div><span>{externalColumnName}</span></div>
);
})}
</div>);
}
});
下面是在 onClick 事件上传递值的示例。
我使用 es6 语法。记住在类组件中箭头函数不会自动绑定,所以在构造函数中显式绑定。
class HeaderRows extends React.Component {
constructor(props) {
super(props);
this.handleSort = this.handleSort.bind(this);
}
handleSort(value) {
console.log(value);
}
render() {
return(
<tr>
{this.props.defaultColumns.map( (column, index) =>
<th value={ column }
key={ index }
onClick={ () => this.handleSort(event.target.value) }>
{ column }
</th>
)}
{this.props.externalColumns.map((column, index) =>
<th value ={ column[0] }
key={ index }>
{column[0]}
</th>
)}
</tr>
);
}
}
我猜你必须将方法绑定到 React 的类实例。使用构造函数绑定 React 中的所有方法更安全。在您将参数传递给方法的情况下,第一个参数用于绑定方法的“this”上下文,因此您无法访问方法内的值。
1. You just have to use an arrow function in the Onclick event like this:
<th value={column} onClick={() => that.handleSort(theValue)} >{column}</th>
2.Then bind this in the constructor method:
this.handleSort = this.handleSort.bind(this);
3.And finally get the value in the function:
handleSort(theValue){
console.log(theValue);
}
使用箭头功能:
您必须安装第 2 阶段:
npm install babel-preset-stage-2 :
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value=0
}
}
changeValue = (data) => (e) => {
alert(data); //10
this.setState({ [value]: data })
}
render() {
const data = 10;
return (
<div>
<input type="button" onClick={this.changeValue(data)} />
</div>
);
}
}
export default App;
有一个非常简单的方法。
onClick={this.toggleStart('xyz')} .
toggleStart= (data) => (e) =>{
console.log('value is'+data);
}
class TableHeader extends Component {
handleClick = (parameter,event) => {
console.log(parameter)
console.log(event)
}
render() {
return (
<button type="button"
onClick={this.handleClick.bind(this,"dataOne")}>Send</button>
);
}
}
突然出现这个问题,但我认为 .bind
会解决问题。找到下面的示例代码。
const handleClick = (data) => {
console.log(data)
}
<button onClick={handleClick.bind(null, { title: 'mytitle', id: '12345' })}>Login</button>
有3种方法来处理这个: -
将构造函数中的方法绑定为:- export class HeaderRows extends Component { constructor() { super(); this.handleSort = this.handleSort.bind(this); } } 创建时使用箭头函数:- handleSort = () => { // 这里有一些文本 } 第三种方式是这样的:-
您可以像这样使用您的代码:
<th value={column} onClick={(e) => that.handleSort(e, column)} >{column}</th>
这里 e 代表事件对象,如果您想在句柄函数中使用像 preventDefault()
这样的事件方法,或者想要获得像 e.target.name
这样的目标值或名称。
有很多性能方面的考虑,都是在真空中的。这个处理程序的问题是您需要对它们进行curry,以便将您无法在道具中命名的参数合并。这意味着该组件需要一个处理程序来处理每个可点击的元素。让我们同意,对于几个按钮来说,这不是问题,对吧?当您处理具有数十列和数千行的表格数据时,就会出现问题。在那里,您会注意到创建这么多处理程序的影响。
事实是,我只需要一个。我将处理程序设置在表级别(或 UL 或 OL ...),当点击发生时,我可以使用事件对象中的可用数据来判断哪个是点击的单元格:
nativeEvent.target.tagName
nativeEvent.target.parentElement.tagName
nativeEvent.target.parentElement.rowIndex
nativeEvent.target.cellIndex
nativeEvent.target.textContent
我使用标记名字段来检查点击是否发生在有效元素中,例如忽略在 TH 和页脚中的点击。 rowIndex 和 cellIndex 给出了被点击单元格的准确位置。 Textcontent 是单击单元格的文本。
这样我就不需要将单元格的数据传递给处理程序,它可以自助服务。如果我需要更多数据,即不显示的数据,我可以使用数据集属性或隐藏元素。通过一些简单的 DOM 导航,一切都触手可及。从那时起,这一直在 HTML 中使用,因为 PC 更容易陷入困境。
当使用函数而不是类时,它实际上相当容易。
const [breakfastMain, setBreakFastMain] = useState("Breakfast");
const changeBreakfastMain = (e) => {
setBreakFastMain(e.target.value);
//sometimes "value" won't do it, like for text, etc. In that case you need to
//write 'e.target/innerHTML'
}
<ul onClick={changeBreakfastMain}>
<li>
"some text here"
</li>
<li>
"some text here"
</li>
</ul>
我会这样做:
const HeaderRows = props => {
const handleSort = value => () => {
}
return <tr>
{props.defaultColumns.map((column, i) =>
<th key={i} onClick={handleSort(column)}>{column}</th>)}
{props.externalColumns.map((column, i) => {
// Multi dimension array - 0 is column name
const externalColumnName = column[0]
return (<th key={i}>{externalColumnName}</th>)
})}
</tr>
}
<a>
标记一起使用,以便使用preventDefault()
bind
传递的参数之后。