Dimitry Ivashchuk
Dimitry Ivashchuk

Reputation: 625

Passing dynamic onChange listener to children

I have a stateful component that holds some state

state={
  name:'',
  age:'',
  occupation:''
}

And a function to update the state onChange listener

onValueChange = (key, event) => {
  this.setState({ [key]: event.target.value });
};

I pass the state and function down to child as props

<ComponentA {...this.state} changed={this.onValueChange}>

Inside my component B which is a child of A I want to programatically create inputs based on given props and change the state by invoking that function every time user types in input.

<ComponentB>

{  Object.entries(this.props)
    .filter(
      prop =>
        prop[0] !== 'changed'
    )
    .map(propName => (
      <Input
        key={propName}
        label={propName[0]}
        value={propName[1]}
        onValueChange={this.props.changed(propName[0])}
      />
    ))}

  </ComponentB>

My Input component just renders the following

  <input
     onChange={this.props.onValueChange}
     value={this.props.value}
     type={this.props.type}
     placeholder="&nbsp;"
   />

Can't make it work for some reason. Thanks for any help!

Upvotes: 2

Views: 81

Answers (1)

Tholle
Tholle

Reputation: 112917

You are currently invoking this.props.changed straight away on render by writing onValueChange={this.props.changed(propName[0])}. Instead of invoking it on render you should give it a function to call when onValueChange occurs instead.

You also want to give the Input a unique key prop that will not change between state updates, so that React doesn't create an entirely new component every time and you e.g. lose focus of the input. You can use propName[0] instead, which will be unique.

<Input
  key={propName[0]}
  label={propName[0]}
  value={propName[1]}
  onValueChange={event => this.props.changed(propName[0], event)}
/>

Upvotes: 1

Related Questions