0

So, the problem is below.

  handleBankAccountInput = (e, key) => {
let name = e.target.name;
let value = e.target.value;
let validation = e.target.key;
let bankAccounts = {...this.state.bankAccounts};
let ibanValid = bankAccounts[key].validationState.iban;
let banknameValid = bankAccounts[key].validationState.bankname;
bankAccounts[key][name] = value;

switch(validation) {
  case 'iban':
    ibanValid = IBAN.isValid(value); // true
    bankAccounts[key].fieldValidationErrors.iban = ibanValid ? '' : ' is invalid IBAN';
    bankAccounts[key].validationState.iban = ibanValid ? 'success' : 'error';
    console.log("why validate all iban of bankAccounts of key: " + key );
    console.log(bankAccounts[key]);

    break;
  case 'bankname':
    banknameValid = value.length >=1; // true
    bankAccounts[key].fieldValidationErrors.bankname = banknameValid ? '' : ' is invalid bankname';
    bankAccounts[key].validationState.bankname = banknameValid ? 'success' : 'error';
    console.log("why validate all bankname of bankAccounts of key: " + key );
    console.log(bankAccounts[key]);
    break;
  default:
    break;
}

// bankAccounts[key] = bankAccount;
this.setState({bankAccounts: bankAccounts}, this.validateForm);
bankAccounts = {};
}

Problem:

The line ' bankAccounts[key].fieldValidationErrors.iban = ibanValid ? '' : ' is invalid IBAN'; ' is triggered by other inputs with same name attribute.

  addBankAccountInput = () => {
let bankAccounts = {...this.state.bankAccounts};
// add in our new menu
let bankAccount = {...this.state.bankAccount};
bankAccount['iban'] = '';
bankAccount['bankname'] = '';
bankAccount['validationState']['iban'] = '';
bankAccount['validationState']['bankname'] = '';
bankAccount['formErrors']['iban'] = '';
bankAccount['formErrors']['bankname'] = '';
bankAccount['fieldValidationErrors']['iban'] = '';
bankAccount['fieldValidationErrors']['bankname'] = '';

let accountnum = 0;
if(bankAccounts) {
  Object.keys(bankAccounts).map((key) => accountnum++ );
}

bankAccounts[accountnum] = bankAccount;
this.setState({ bankAccounts: bankAccounts });
bankAccount = {};
bankAccounts = {};
}

This is how I add empty bankAccount inputs.

  renderBankAccountInput = (key) => {
return (
  <div key={key}>
    <FormGroup controlId={'formHorizontalBankAccount'+key} validationState={this.state.bankAccounts[key].validationState.iban}>
      <Col componentClass={ControlLabel} sm={2}>
        IBAN
      </Col>
      <Col sm={10}>
        <FormControl type="text" name={'iban'+key} key='iban' value={this.state.bankAccounts[key].iban} placeholder="iban" onChange={(e) => this.handleBankAccountInput(e, key)} />
      </Col>
      <FormControl.Feedback />
      <HelpBlock>{this.state.bankAccounts[key].formErrors.iban}</HelpBlock>
    </FormGroup>
    <FormGroup controlId={'formHorizontalBankAccount' + key} validationState={this.state.bankAccounts[key].validationState.bankname}>
      <Col componentClass={ControlLabel} sm={2}>
        Bankname
      </Col>
      <Col sm={10}>
        <FormControl type="text" name={'bankname'+key} key='bankname' value={this.state.bankAccounts[key].bankname} placeholder="Bank name" onChange={(e) => this.handleBankAccountInput(e, key)} />
      </Col>
      <FormControl.Feedback />
      <HelpBlock>{this.state.bankAccounts[key].formErrors.bankname}</HelpBlock>
    </FormGroup>
  </div>
)
}

This is how I render inputs.

Like this.

Bank accounts

    {Object.keys(this.state.bankAccounts).map(this.renderBankAccountInput)}
    { this.state.bankAccounts.length < 1 &&
      <HelpBlock>You should provide at least one bank account</HelpBlock>
    }
    <button
      onClick={(e) => {
        e.preventDefault();
        this.addBankAccountInput();
      }}
    >Add Bank Account</button>`

Would appreciate your help!

Mikhail_Sam
  • 10,602
  • 11
  • 66
  • 102

1 Answers1

0

It is due to a tricky and headache problem of React. You are using the array index as the key to mapped components by this line <div key={key}>. It makes React confused when updating the array, to which property belong to which component and leads to an unpredictable result.

You can refer to this SO answer with more explanation about the issue in Preact, which is an alternative to React. The explanation can also be applied in React as well.

Solution:

  • Generate an uuid to your component list. There are my library provides this feature like lodash-uuid or shortid
  • In your situation, you can use bankAccounts[key][iban] as your component key.
An Nguyen
  • 1,487
  • 10
  • 21