2

I have bunch of inputs and I do not want to have multiple handlers like

handleInput1(){},handleInput2(){} and so on.

But I have difficulties producing below array of object

[{
  name: 3,
  value: 1000
},{
  name: 5,
  value: 1000
}]

how can I by using listen to only one handler and use setState in react?

http://jsbin.com/godesacici/edit?js,console,output

Alex
  • 2,325
  • 16
  • 17
Alan Jenshen
  • 2,569
  • 8
  • 18
  • 30

5 Answers5

0

You can try to do it the follwoing way by distinguishing the different inputs by the name attribute and storing the result in the state

class HelloWorldComponent extends React.Component {
  constructor(){
    super();
    this.state = {
      result: []
    }
  }
  handleInput(e) {
      console.log(e.target.value);
      var result = [...this.state.result];
      var idx = result.map(function(val){ return val.name}).indexOf(e.target.name);
      if(idx > -1) {
          result[idx].value=e.target.value;
      } else {
        result.push({name: e.target.name, value:e.target.value});
      }
       this.setState({result})
  }

  handleClick() {
    console.log(this.state.result);
  }

  render() {
    return (      
      <div>
      <div><input type="number" name="4" onChange={this.handleInput.bind(this)}/></div>
      <div><input type="number" name="3" onChange={this.handleInput.bind(this)}/></div>
      <div><input type="number" name="5" onChange={this.handleInput.bind(this)}/></div>
        <button onClick={this.handleClick.bind(this)}>submit</button>
      </div>
    );
  }
}

React.render(
  <HelloWorldComponent name="Joe Schmoe"/>,
  document.getElementById('react_example')
);

JSBIN

Shubham Khatri
  • 211,155
  • 45
  • 305
  • 318
0

So you can be explicit and bind the key string onto a single handler function like so:

_handleInput(key, val) {
  let { ..state } = this.state;
  state[key] = val;
  this.setState(state);
}
render() {
  return <div>
           <input
            onChange={this.handleInput.bind(null, key1)}
            value={this.state.key1} />
           <input
            onChange={this.handleInput.bind(null, key2)}
            value={this.state.key2} />
         </div>
}
Michael Lyons
  • 554
  • 3
  • 9
0

you can add name property to input, and get target.name like this:

_handleInput(event) {
    let name = event.target.name;
    let value = event.target.value;
  this.setState({[name] : value});
}

<input
    onChange={this._handleInput}
    value={this.state.key1} 
    name="key1"
/>
Lojka
  • 157
  • 8
0

If you change your state model to have a key per form element and use some nice-to-haves like arrow functions to capture variable scope in a cleaner syntax, you can simplify things:

class HelloWorldComponent extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      "3": {},
      "4": {},
      "5": {}
    }
  }

  handleInput(name, value) {
    this.setState({
      [name]: {
        name: name,
        value: value
      }
    });
  }

  handleClick() {
    console.log(this.state); 
  }

  render() {
    return (      
      <div>
      <div><input type="number" value={this.state["3"].value} onChange={(e) => this.handleInput(3, e.target.value)}/></div>
      <div><input type="number" value={this.state["4"].value} onChange={(e) => this.handleInput(4, e.target.value)}/></div>
      <div><input type="number" value={this.state["5"].value} onChange={(e) => this.handleInput(5, e.target.value)}/></div>
      <button onClick={(e) => this.handleClick()}>submit</button>
      </div>
    );
  }
}

React.render(
  <HelloWorldComponent name="Joe Schmoe"/>,
  document.getElementById('react_example')
);

Having your state be an array of values not keyed by anything will force you to search through the state and replace it (as some of the other answers have shown).

It's usually a better idea to simplify things to improve readability and comprehension

Recall that React state is additive, so calling setState with just a partial state change will merge it with the existing state. You will only get this benefit if you're keying your data in the state.

Alex
  • 2,325
  • 16
  • 17
0

Since it's an an array you want to modify you can use array indices. Suppose the initial state is this.

this.state = {
  array: [{
    name: 3,
    value: 1000
  },{
    name: 5,
    value: 1000
  }]
}

Then the inputs can be like this (for the one with name 3 which has index 0)

<input value={this.state.array[0].value} onChange={this.handleChange.bind(this,0)}/>

So the value it will display is for the 1st element in the array (with index 0) and the handleChange binds to the event as well as pass the index 0.

handleChange(index,event){
this.setState((prevState) => ({array:[  
        ...prevState.array.slice(0, index),
        Object.assign({},prevState.array[index],{value:event.target.value}),
        ...prevState.array.slice(index + 1)
        ]}))
}

Ok so this might seem a little complicate but let me try to explain here. So the handleChange method takes two parameters - the event corresponding to the input text and the index which is the array index of the element in the state array (0 in our example). So in this.setState we have taken the prevState and used a bit of splicing. ...prevState.array.slice(0,index) corresponds to all elements of the array before the one we are modifying. ...prevState.slice(index+1) corresponds to all those after. So we take these two sets and join them with the modified element in between. The Object.assign() corresponds to the modified element. What it is doing is taking the prevState.array[index] which is the element we are modifying and setting it's value to event.target.value corresponding to the text.

mrinalmech
  • 1,735
  • 1
  • 17
  • 16
  • `` how can you assume the first item has the name 3? – Alan Jenshen Apr 28 '17 at 05:29
  • Ok, so the elements aren't fixed in the array? If the elements are randomized and the inputs are generated from the array you can do something like ` ` so people will have an idea about which input corresponds to which name. I was assuming you set the initial state yourself. – mrinalmech Apr 28 '17 at 05:36