user578895
user578895

Reputation:

React event listeners on array of elements

My React render function eventually renders a set of elements:

data.map((element) => {
  return <Object onChange={this.onObjectChange} />;
});

My question is what is the appropriate way to figure out which object had its onChange method called when I receive the callback?

Upvotes: 5

Views: 4666

Answers (5)

Dewey
Dewey

Reputation: 1223

To avoid creating an anonymous function in every render, you could have a function that creates the handlers like this (I am using Todo App as an example):

createOnChangeEventHandler(todo) {
    const { onToggleClick } = this.props;

    this.handlers = this.handlers || {};
    if (!this.handlers[todo.id]) {
      this.handlers[todo.id] = () => onToggleClick(todo.id);
    }

    return this.handlers[todo.id];
  }

... Then in render()

{todos.map(todo => (<Todo key={todo.id} onClick={this.createOnChangeEventHandler(todo)} />))}

Upvotes: 0

Seth Jeffery
Seth Jeffery

Reputation: 1120

If you can, pass the ID or element to the component you're creating, then pass that reference back to your event handler.

handleObjectChange = id => {
  const object = data.find(id)
}

render() {
  return data.map((element, index) => (
    <Object onChange={this.handleObjectChange} key={element.id} id={element.id} />
  ))
  // or just pass element={element} to track the object itself, why not?
  // after all, every array item's key must be unique
}

In Object...

function change() {
  const { onChange, id } = this.props
  onChange(id)
}

Is your Object closed, or prefer not to add an extra property? You could try wrapping it.

class IdentifiedButton extends Component {
  handleClick = (event, ...args) => {
    const { id, onClick } = this.props
    onClick(event, id, ...args)
  }

  render() {
    const { id, onClick, ...props } = this.props
    return <Button onClick={this.handleClick} {...props} />
  }
}

Upvotes: 1

berrtech
berrtech

Reputation: 328

If rerendering your Object component won't cost you that much I would go with something like this

data.map(element => <Object onChange={() => this.onObjectChange(element)} />);

If Object component is quite heavyweight you better pass element to Object component and then pass it to onChange callback

data.map(element => (
  <Object
    key={element.id} 
    onChange={this.onObjectChange} 
    element={element}
  />
);

class Object extends React.Component {
  handleChange = () => this.props.onChange(this.props.element)

  render(){
    return (
      <input type='text' onChange={this.handleChange} />
    )
  }
}

Upvotes: 0

TimoStaudinger
TimoStaudinger

Reputation: 42450

Wrap the callback in a function and pass an identifier:

data.map(element => <Object onChange={event => this.onObjectChange(element.id, event)} />);

Upvotes: 0

Dave Cooper
Dave Cooper

Reputation: 10714

The first parameter to the onSubjectChange function will have your event which contains the event information.

Hope that helps!

Upvotes: 1

Related Questions