Kris
Kris

Reputation: 187

update state in nested array react.js

I am trying to get two way binding to work for a nested array in react. I have it working for department name which is a simple single input. The problem is when I try to setState for my team array in handleInputChangeArray. The app breaks and I get an error that says this.state.team.map is not a function.

  constructor(props) {
    super(props);
    this.state = {
      departmentName: '',
      team: [
        {
          name: '',
          title: '',
          salary: '',  
            }
          ]
        }
      ]

    };
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleInputChangeArray = this.handleInputChangeArray.bind(this);
  }

These are my two functions:

handleInputChangeArray(event) {
 const target = event.target;
 const value = target.type === 'checkbox' ? target.checked : target.value;
 const name = target.name;
 this.setState(({team}) => ({team: {
      ...team,
      [name]: value,
    }}))
  }

handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
  [name]: value
 });
}

This input works perfectly with my handleInputChange

 <input  className="form-control" name=“departmentName” defaultvalue={this.state.departmentName} onChange={this.handleInputChange} type="text" />

This does not work:

{this.state.team.map(( listValue, index ) => {
  return (
    <td key={index}>
      <input type="text" className="form-control" name="listValue.name" defaultValue={listValue.name}  onChange={this.handleInputChangeArray}  />
    </td>
    );
  })}

Upvotes: 3

Views: 10660

Answers (1)

Tholle
Tholle

Reputation: 112777

You also have to pass in the index of which object in your team array that should be updated, so that you can create a new object with the name property changed to value for the right element.

Example

class App extends React.Component {
  handleInputChangeArray(event, index) {
    const { target } = event;
    const { name } = target;
    const value = target.type === "checkbox" ? target.checked : target.value;

    this.setState(prevState => {
      const team = [...prevState.team];
      team[index] = { ...team[index], [name]: value };
      return { team };
    });
  }

  render() {
    return (
      <tr>
        {this.state.team.map((listValue, index) => {
          return (
            <td key={index}>
              <input
                type="text"
                className="form-control"
                name="name"
                defaultValue={listValue.name}
                onChange={event => this.handleInputChangeArray(event, index)}
              />
            </td>
          );
        })}
      </tr>
    );
  }
}

Upvotes: 7

Related Questions