简体   繁体   中英

How do I handle onChange of objects inside an array (React State)?

community,

I'm trying to build a table where its rows are rendered based on an array of objects:

this.state = {
  tableContent: [
    { 
      id: this.state.tableContent.length,
      firstname:"",
      lastname:""
    },
    ...
  ]

Each row displays one object. (2 columns in this case, n rows) Each cell is also an input field, so users can manipulate the table:

<tbody>
  {this.state.tableContent.map((row) => {
    return(
      <tr key={row.id}>
        <td><input value={row.firstname} onChange={this.handleFirstNameChange}> </input></td>
        ...
      </tr>
    )
  })}
</tbody>

I want each cell / input field to display the change when the user changes the input value and as such the state. Because I'm prepopulating the input field with value={row.firstname} I need to define an onChange handler function that changes the state/value of the target object's firstname property.

So how does my onChange handler function look like? I tried using spreads, but to no avail so far...

Some thoughts: Using the standard procedure doesn't work because I have a nested state (Array of objects):

handleChange = (event) => { this.setState({ firstname: event.target.value }) } 

Trying to use the spread operator results in some weird mess as well: (this code here is somewhat wrong: maybe you can fix it?)

handleFirstNameChange = (event) => {
    const {tableContent} = {...this.state};
    const currentState = tableContent;
    const { firstname, value } = event.target;
    currentState[0] = value;
    this.setState({ tableContent: currentState});
  }

I appreciate any help!

edit: The code below seems to nearly work. (thanks @Nikhil ) However now, whenever the user types into the input field, every letter they type will replace the existing letter / value of 'row.firstname'. Also, state doesn't refresh automatically so only the last-typed letter would show up / persist. What I need the input field to have is a functionality just like any casual input field. event.persist(); seems to be needed to keep the event value.

handleFirstNameChange = (id, event) => {
    event.persist(); 
    this.setState(prevState => {
      tableContent : prevState.tableContent.forEach((row) => {
        if(row.id === id) { row.firstname = event.target.value}
      })
    })
  }

input looks like this:

onChange={(event) => this.handleWNRChange(row.id,event)}

I think something like this would work.

const handleFirstNameChange = (id, event) => {
    event.preventDefault();
    const {tableContext} = this.state;

    const myRowIndex = tableContext.findIndex((row) => row.id === id);
    tableContext[myRowIndex].firstname = event.target.value;

    this.setState({ tableContext });
}

This should be all you need. Just assign this method to the onChange of the input element. Like so:

onChange={(event) => this.handleFirstNameChange(row.id, event)}

May be this will help

{this.state.tableContent.map((row, index) => {
    return(
      <tr key={row.firstname}>
        <td><input value={row.firstname}
             onChange={(event)=>this.handleFirstNameChange(event, index)> </input></td>
      </tr>
    )
  })
}

handleFirstNameChange(event, index){
  this.setState((prevState => {
      tableContent : prevState.tableContent.forEach((row,i)=>{
        if(index === i) row.firstname = event.target.value
      })
  })
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM