React js onClick can't pass value to method

后端 未结 30 1729
北荒
北荒 2020-11-22 07:05

I want to read the onClick event value properties. But when I click on it, I see something like this on the console:

SyntheticMouseEvent {dispatchConfig: Ob         


        
相关标签:
30条回答
  • 2020-11-22 07:35

    I guess you will have to bind the method to the React’s class instance. It’s safer to use a constructor to bind all methods in React. In your case when you pass the parameter to the method, the first parameter is used to bind the ‘this’ context of the method, thus you cannot access the value inside the method.

    0 讨论(0)
  • 2020-11-22 07:35

    There are couple of ways to pass parameter in event handlers, some are following.

    You can use an arrow function to wrap around an event handler and pass parameters:

    <button onClick={() => this.handleClick(id)} />
    

    above example is equivalent to calling .bind or you can explicitly call bind.

    <button onClick={this.handleClick.bind(this, id)} />
    

    Apart from these two approaches, you can also pass arguments to a function that is defined as a curry function.

    handleClick = (id) => () => {
        console.log("Hello, your ticket number is", id)
    };
    
    <button onClick={this.handleClick(id)} />
    
    0 讨论(0)
  • 2020-11-22 07:35

    I found the solution of passing param as a tag's attribute quite reasonable.

    However it has limitations:

    • Doesn't work properly when list item has other tags (thus event.target might be different to intended)
    • Param could be a string only. Requires serialization and deserialization.

    That's why I came up with this library: react-event-param

    It:

    • Solves the problem of children by searching for needed attribute in parents whenever needed
    • Automatically serializes and deserializes param
    • Encapsulates the logic of setting and getting. No need to mess with param names

    Usage example:

    import { setEventParam, getEventParam } from "react-event-param";
    
    class List extends Component {
      onItemClick = e => {
        const index = getEventParam(e.target);
        // Do something with index
      };
    
      render() {
        return (
          <ul>
            {this.props.items.map((itemText, index) => (
              <li
                key={index}
                {...setEventParam(index)}
                onClick={this.onItemClick}
              >
                {{ itemText }}
              </li>
            ))}
          </ul>
        );
      }
    }
    
    export default List;
    
    0 讨论(0)
  • 2020-11-22 07:36

    One more option not involving .bind or ES6 is to use a child component with a handler to call the parent handler with the necessary props. Here's an example (and a link to working example is below):

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

    The basic idea is for the parent component to pass the onClick function to a child component. The child component calls the onClick function and can access any props passed to it (and the event), allowing you to use any event value or other props within the parent's onClick function.

    Here's a CodePen demo showing this method in action.

    0 讨论(0)
  • 2020-11-22 07:36

    You just need to use Arrow function to pass value.

    <button onClick={() => this.props.onClickHandle("StackOverFlow")}>

    Make sure to use () = >, Otherwise click method will be called without click event.

    Note : Crash checks default methods

    Please find below running code in codesandbox for the same.

    React pass value with method

    0 讨论(0)
  • 2020-11-22 07:38

    There are nice answers here, and i agree with @Austin Greco (the second option with separate components)
    There is another way i like, currying.
    What you can do is create a function that accept a parameter (your parameter) and returns another function that accepts another parameter (the click event in this case). then you are free to do with it what ever you want.

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

    And you will use it this way:

    <input 
        type="text" 
        onChange={this.handleChange(someParam)} 
    />
    

    Here is a full example of such usage:

    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>

    Note that this approach doesn't solve the creation of a new instance on each render.
    I like this approach over the other inline handlers as this one is more concise and readable in my opinion.

    Edit:
    As suggested in the comments below, you can cache / memoize the result of the function.

    Here is a naive implementation:

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

    0 讨论(0)
提交回复
热议问题