Je veux ajouter une bordure rouge uniquement si une entrée est vide. Je ne pouvais pas trouver un moyen d'ajouter "addClass" dans React, donc j'utilise state. À l'heure actuelle, le code ajoutera une bordure rouge à toutes les entrées, même s'il contient du texte.

Etat:

this.state = {
  inputBorderError: false,
};

HTML / JSX:

<label>Name</label>
<input className={
  this.state.inputBorderError ? 'form-input form-input-fail' : 'form-input'
} />

<label>Email</label>
<input className={
  this.state.inputBorderError ? 'form-input form-input-fail' : 'form-input'
} />

<label>Message</label>
<textarea className={
  this.state.inputBorderError ? 'form-input form-input-fail' : 'form-input'
} />

CSS:

.form-input-fail {
  border: 1px solid red;
}

JS:

   let inputFields = document.getElementsByClassName('form-input');

   for (var i = 0; i < inputFields.length; i++) {
      if (inputFields[i].value === '') {
        this.setState({
          inputBorderError: true,
        });
      }
    }

Je vois l'erreur dans mon code car il définit essentiellement l'état à vrai chaque fois qu'il trouve une entrée vide. Je pense que je peux aborder cela incorrectement car il n'y a qu'un seul état. Existe-t-il une solution basée sur mon approche étatique ou existe-t-il une autre solution?

2
Eric Nguyen 18 juin 2019 à 23:48

3 réponses

Meilleure réponse

À l'heure actuelle, vous avez une seule valeur d'état qui affecte toutes les entrées, vous devriez envisager d'en avoir une pour chaque input. De plus, vos entrées ne sont pas contrôlées, il sera plus difficile d'enregistrer et de suivre leurs valeurs pour la gestion des erreurs.

Il est recommandé de donner à chaque balise input une propriété de nom. Facilitant la mise à jour dynamique de leur valeur d'état correspondante.

Essayez quelque chose comme le suivant, commencez à taper dans chaque entrée, puis supprimez votre texte: https: // codesandbox .io / s / nerveux-feynman-vfmh5

class App extends React.Component {
  state = {
    inputs: {
      name: "",
      email: "",
      message: ""
    },
    errors: {
      name: false,
      email: false,
      message: false
    }
  };

  handleOnChange = event => {
    this.setState({
      inputs: {
        ...this.state.inputs,
        [event.target.name]: event.target.value
      },
      errors: {
        ...this.state.errors,
        [event.target.name]: false
      }
    });
  };

  handleOnBlur = event => {
    const { inputs } = this.state;
    if (inputs[event.target.name].length === 0) {
      this.setState({
        errors: {
          ...this.state.errors,
          [event.target.name]: true
        }
      });
    }
  };

  handleOnSubmit = event => {
    event.preventDefault();
    const { inputs, errors } = this.state;
    //create new errors object
    let newErrorsObj = Object.entries(inputs)
      .filter(([key, value]) => {
        return value.length === 0;
      })
      .reduce((obj, [key, value]) => {
        if (value.length === 0) {
          obj[key] = true;
        } else {
          obj[key] = false;
        }
        return obj;
      }, {});

    if (Object.keys(newErrorsObj).length > 0) {
      this.setState({
        errors: newErrorsObj
      });
    }
  };

  render() {
    const { inputs, errors } = this.state;
    return (
      <div>
        <form onSubmit={this.handleOnSubmit}>
          <label>Name</label>
          <input
            className={
              errors.name ? "form-input form-input-fail" : "form-input"
            }
            name="name"
            value={inputs.name}
            onChange={this.handleOnChange}
            onBlur={this.handleOnBlur}
          />

          <label>Email</label>
          <input
            className={
              errors.email ? "form-input form-input-fail" : "form-input"
            }
            name="email"
            value={inputs.email}
            onChange={this.handleOnChange}
            onBlur={this.handleOnBlur}
          />

          <label>Message</label>
          <textarea
            className={
              errors.message ? "form-input form-input-fail" : "form-input"
            }
            name="message"
            value={inputs.message}
            onChange={this.handleOnChange}
            onBlur={this.handleOnBlur}
          />
          <button type="submit">Submit</button>
        </form>
      </div>
    );
  }
}
4
Christopher Ngo 18 juin 2019 à 21:22

Vous avez raison, il n'y a qu'un seul état.

Ce que vous devez faire est de stocker une erreur distincte pour chaque entrée. une façon de le faire est avec un ensemble ou un tableau sur un état comme state = {errors: []}, puis vérifiez

<label>Name</label>
<input className={
  this.state.errors.includes('name') ? 'form-input form-input-fail' : 'form-input'
} />

<label>Email</label>
<input className={
  this.state.errors.includes('email') ? 'form-input form-input-fail' : 'form-input'
} />
} />
0
aaronmgdr 18 juin 2019 à 21:00

Vous devez garder une trace de la valeur d'entrée dans l'état au lieu de vérifier l'état borderStyling uniquement.

Sur la base de votre code, vous pouvez le refactoriser en quelque chose comme ceci:

// keep track of your input changes
this.state = {
  inputs: {
    email: '',
    name: '',
    comment: '',
  },
  errors: {
    email: false,
    name: false,
    comment: false,
  }
};

// event handler for input changes

handleChange = ({ target: { name, value } }) => {
    const inputChanges = {
       ...state.inputs,
       [name]: value
    }

    const inputErrors = {
       ...state.errors,
       [name]: value == ""
    }

    setState({
      inputs: inputChanges,
      errors: inputErrors,
    });
}

HTML / JSX

// the name attribut for your input

<label>Name</label>
<input name="name" onChange={handleChange} className={
  this.errors.name == "" ? 'form-input form-input-fail' : 'form-input'
} />

<label>Email</label>
<input name="email" onChange={handleChange} className={
  this.errors.email == "" ? 'form-input form-input-fail' : 'form-input'
} />

<label>Message</label>
<textarea name="comment" onChange={handleChange} className={
  this.errors.comment == "" ? 'form-input form-input-fail' : 'form-input'
} />

Et si vous envisagez probablement de l'implémenter avec CSS et js, vous pouvez essayer cet article faire correspondre une boîte de saisie vide à l'aide de css et js

Mais essayez d'apprendre à rendre votre composant réutilisable et sec, car c'est le début de profiter de l'application React.

[Modifié]

0
akolliy 18 juin 2019 à 22:02