React js onClick无法将值传递给方法

use*_*375 563 javascript reactjs

我想阅读onClick事件值属性.但是当我点击它时,我在控制台上看到类似的东西:

SyntheticMouseEvent {dispatchConfig: Object, dispatchMarker: ".1.1.0.2.0.0:1", nativeEvent: MouseEvent, type: "click", target
Run Code Online (Sandbox Code Playgroud)

我的代码工作正常.当我运行时,我可以看到{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>
    );
  }
});
Run Code Online (Sandbox Code Playgroud)

如何将值传递给onClickReact js中的事件?

Aus*_*eco 1159

简单的方法

使用箭头功能:

return (
  <th value={column} onClick={() => this.handleSort(column)}>{column}</th>
);
Run Code Online (Sandbox Code Playgroud)

这将创建一个handleSort使用正确的参数调用的新函数.

更好的方法

将其解压缩为子组件. 在渲染调用中使用箭头函数的问题是它每次都会创建一个新函数,最终导致不需要的重新渲染.

如果你创建一个子组件,你可以传递处理程序并使用props作为参数,然后只有当props更改时才重新呈现(因为处理程序引用现在永远不会改变):

子组件

class TableHeader extends Component {
  handleClick = () => {
    this.props.onHeaderClick(this.props.value);
  }

  render() {
    return (
      <th onClick={this.handleClick}>
        {this.props.column}
      </th>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

主要成分

{this.props.defaultColumns.map((column) => (
  <TableHeader
    value={column}
    onHeaderClick={this.handleSort}
  />
))}
Run Code Online (Sandbox Code Playgroud)

Old Easy Way(ES5)

使用.bind通过所需要的参数:

return (
  <th value={column} onClick={that.handleSort.bind(that, column)}>{column}</th>
);
Run Code Online (Sandbox Code Playgroud)

  • 这对性能不是很糟糕吗?不会在每个渲染上创建新函数? (43认同)
  • @SimonH在通过`bind`传递的参数之后,事件将作为最后一个参数传递. (37认同)
  • 你如何使用`<a>`标签,你需要传递事件,以便使用`preventDefault()` (12认同)
  • @AndrewMcLagan是的.我[发现这个](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md)来描述规则和最高性能的解决方案. (11认同)
  • 当我像你的代码一样使用时,react会发出警告.我将我的代码更改为onClick = {that.onClick.bind(null,column)} (7认同)
  • 这个答案是完全错误的.如果你使用它,你每次都会在onClick = {()=> this.handleSort(column)}内获得新的函数引用,每个渲染DOM都会不同,并且必须对它进行更新.它打破了React和解. (6认同)
  • 简单的方法:3行代码。更好的方法:13行代码。猜猜谁赢了? (3认同)
  • `bind`是常规javascript(ES5)的一部分 - 查看MDN上[`.bind`的文档](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects /功能/绑定) (2认同)
  • @AlexShwarc是的,这就是答案的“更好的方式”部分的原因,它不会在每个渲染器上都创建一个新函数:) (2认同)
  • 感谢您提供“更好的方式”。这非常有用。 (2认同)

Sag*_*b.g 122

这里有很好的答案,我同意@Austin Greco(第二个选项有单独的组件)
还有另一种我喜欢的方式,currying.
你可以做的是创建一个接受参数(你的参数)的函数,并返回另一个接受另一个参数的函数(在这种情况下是click事件).然后你随心所欲地随心所欲.

ES5:

handleChange(param) { // param is the argument you passed to the function
    return function (e) { // e is the event object that returned

    };
}
Run Code Online (Sandbox Code Playgroud)

ES6:

handleChange = param => e => {
    // param is the argument you passed to the function
    // e is the event object that returned
};
Run Code Online (Sandbox Code Playgroud)

你会用这种方式使用它:

<input 
    type="text" 
    onChange={this.handleChange(someParam)} 
/>
Run Code Online (Sandbox Code Playgroud)

以下是此类用法的完整示例:

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);
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

请注意,此方法无法解决在每个渲染上创建新实例的问题.
我喜欢这种方法而不是其他内联处理程序,因为在我看来,这个方法更简洁,更易读.

编辑:
如下面的注释中所建议,您可以缓存/记忆功能的结果.

这是一个天真的实现:

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);
Run Code Online (Sandbox Code Playgroud)
<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" />
Run Code Online (Sandbox Code Playgroud)

  • 看起来更好,但是从性能的角度来看,currying并没有真正的帮助,因为如果你使用相同的param调用handleChange两次,你会得到两个JS引擎认为是独立对象的函数,即使它们做同样的事情也是如此.所以你仍然可以重新渲染.为了提高性能,您需要缓存handleChange的结果以获得性能优势.像`handleChange = param => cache [param] || (e => {//函数体})` (25认同)
  • 这应该是公认的答案.真的很容易实现,您不需要创建任何其他组件或绑定不同.谢谢! (12认同)
  • 如果您满足@travellingprog的建议,这是完美的答案 (6认同)
  • 任何人都可以提供链接或解释这种缓存机制如何工作?谢谢. (2认同)
  • 美丽而整洁! (2认同)
  • 是的,currying是要走的路.我同意@Tamb,它应该是公认的答案.您可以在本文中阅读有关该主题的更多信息:[参数化事件处理程序](https://medium.freecodecamp.org/reactjs-pass-parameters-to-event-handlers-ca1f5c422b9) (2认同)
  • 如果使用currying,则将在每个渲染中创建新功能。传递箭头功能会发生相同的性能问题。 (2认同)

aik*_*eru 112

如今,有了ES6,我觉得我们可以使用更新的答案.

return (
  <th value={column} onClick={()=>this.handleSort(column)} >{column}</th>
);
Run Code Online (Sandbox Code Playgroud)

基本上,(对于任何不知道的人)因为onClick期望传递给它的函数,bind因为它创建了函数的副本.相反,我们可以传递一个箭头函数表达式,它只是调用我们想要的函数,并保留this.您永远不需要render在React中绑定该方法,但如果由于某种原因您this在某个组件方法中丢失:

constructor(props) {
  super(props);
  this.myMethod = this.myMethod.bind(this);
}
Run Code Online (Sandbox Code Playgroud)

  • 你永远不需要绑定`render()`,因为它是由React调用的.如果有的话,你需要`绑定'事件处理程序,并且只有当你不使用箭头时. (8认同)
  • 注意,最好将`props`传递给`super()`或`this.props`在构造函数中将是未定义的,这会让人感到困惑. (3认同)
  • 要实现什么?您可以在功能组件内定义处理程序并传递它.每个渲染都将是一个不同的函数,所以*如果你已经确定了一个分析器,它会给你一个问题*(并且只有你真的确定这个!),考虑使用一个类. (2认同)
  • 谢谢爱可如。好的,所以您是说,如果您将 foo 方法声明为类本身的箭头函数,然后使用 this 上下文引用它,那么它只创建一次,而不是在 onClick 中声明它,每次单击时它都会创建相同的函数按钮。我的想法是否正确。 (2认同)
  • @zuckerburg onClick={() =&gt; alert('hi')} 不会立即发出警报, onClick={this.showAlert} 也不会,因为在这两种情况下,您都在传递(不调用)一个函数。 (2认同)

Bra*_*don 70

[[h/t @ E.Sundin 在评论中链接此内容 ]

最顶层的答案(匿名函数或绑定)将起作用,但它并不是最高效的,因为它为map()函数生成的每个实例创建了事件处理程序的副本.

这是对从ESLint-plugin-react执行此操作的最佳方式的解释:

物品清单

渲染中的一个常见用例是渲染列表时,每个列表项都有一个单独的回调:

const List = props => (
      <ul>
        {props.items.map(item =>
          <li key={item.id} onClick={() => console.log(item.id)}>
            ...
          </li>
        )}
      </ul>
    );
Run Code Online (Sandbox Code Playgroud)

而不是这样做,将重复的部分拉入其自己的组件:

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

});
Run Code Online (Sandbox Code Playgroud)

这将加速渲染,因为它避免了在每个渲染上创建新函数(通过绑定调用)的需要.

  • 嗯,我不明白这是多么高效?每次都不会调用ListItem函数,因此每次渲染都会创建_onClick函数. (3认同)
  • @CarlosMartinez很好的眼睛,我更新了这个例子 - 他们应该首先是无状态功能组件(SFC).通常,如果组件不使用`this.state`,则可以安全地将其与SFC交换. (2认同)

Tom*_*dil 34

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>
  )
}
Run Code Online (Sandbox Code Playgroud)

您可以将函数传递给 useCallback 的返回,然后可以通过向其传递参数来在渲染中正常调用您的函数。奇迹般有效!只需确保正确设置 useCallback 的依赖项数组即可。

React >= 16 的最佳解决方案

我发现在 onClick、onChange 等中调用具有多个参数的函数而不使用内联函数的最简洁方法是使用dataReact 16 及更高版本中提供的自定义属性。

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" />
  )
}
Run Code Online (Sandbox Code Playgroud)

上面的示例适用于功能组件,但即使在类组件中,实现也非常相似。

这种方法不会产生不必要的重新渲染,因为您没有使用内联函数,并且避免了与this.

它允许您传递您想要在函数中使用的任意数量的值。

如果您将值作为 props 传递给子组件以在子组件的 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>
  )
}
Run Code Online (Sandbox Code Playgroud)


San*_*rez 23

这是我的方法,不确定它有多糟糕,请评论

在可点击元素中

return (
    <th value={column} onClick={that.handleSort} data-column={column}>   {column}</th>
);
Run Code Online (Sandbox Code Playgroud)

然后

handleSort(e){
    this.sortOn(e.currentTarget.getAttribute('data-column'));
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为这是一个很好的解决方案,因为它非常简单.但它只适用于字符串值,如果你想要一个它不起作用的对象. (2认同)

han*_*man 17

这个例子可能与你的有点不同.但我可以向您保证,这是您可以解决此问题的最佳解决方案.我已经搜索了几天没有性能问题的解决方案.最后想出了这一个.

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>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

UPDATE

如果你想处理应该是参数的对象.您可以使用JSON.stringify(object)它转换为字符串并添加到数据集.

return (
   <div>
     <h3 data-param={JSON.stringify({name:'me'})} onClick={this.handleClick}>
        {this.state.name}
     </h3>
   </div>
);
Run Code Online (Sandbox Code Playgroud)

  • 当传递的数据是对象时,这不起作用 (2认同)

Vla*_*ics 9

class extends React.Component {
    onClickDiv = (column) => {
        // do stuff
    }
    render() {
        return <div onClick={() => this.onClickDiv('123')} />
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 相同 - 每次渲染都有新的 DOM。所以 React 每次都会更新 DOM。 (3认同)

Cha*_*nka 8

简单地创建一个这样的函数

  function methodName(params) {
    //the thing  you wanna do
  }
Run Code Online (Sandbox Code Playgroud)

并在您需要的地方调用它

 <Icon onClick = {() => { methodName(theParamsYouwantToPass);} }/>
Run Code Online (Sandbox Code Playgroud)


jhc*_*hnc 7

我意识到这对派对来说已经很晚了,但我认为一个更简单的解决方案可以满足许多用例:

    handleEdit(event) {
        let value = event.target.value;
    }

    ...

    <button
        value={post.id}
        onClick={this.handleEdit} >Edit</button>
Run Code Online (Sandbox Code Playgroud)

我想你也可以使用一个data-属性。

简单,语义。


Po *_*ith 6

交替尝试回答 OP 的问题,包括 e.preventDefault() 调用:

渲染链接 ( ES6 )

<a href="#link" onClick={(e) => this.handleSort(e, 'myParam')}>
Run Code Online (Sandbox Code Playgroud)

组件功能

handleSort = (e, param) => {
  e.preventDefault();
  console.log('Sorting by: ' + param)
}
Run Code Online (Sandbox Code Playgroud)


Bre*_*ody 5

.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);
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

基本思想是让父组件将onClick函数传递给子组件。子组件调用该onClick函数并可以访问任何props传递给它的(和event),允许您event在父onClick函数中使用任何值或其他道具。

这是一个CodePen 演示,展示了此方法的实际应用。


小智 5

如果您正在使用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>
     );
   }
 }
Run Code Online (Sandbox Code Playgroud)


Uma*_*med 5

有几种方法可以在事件处理程序中传递参数,其中一些方法如下。

您可以使用箭头函数来包装事件处理程序并传递参数:

<button onClick={() => this.handleClick(id)} />
Run Code Online (Sandbox Code Playgroud)

上面的例子相当于调用.bind或者你可以显式调用bind。

<button onClick={this.handleClick.bind(this, id)} />
Run Code Online (Sandbox Code Playgroud)

除了这两种方法之外,您还可以将参数传递给定义为 curry 函数的函数。

handleClick = (id) => () => {
    console.log("Hello, your ticket number is", id)
};

<button onClick={this.handleClick(id)} />
Run Code Online (Sandbox Code Playgroud)