09. React - formuláře

17.02.2019 Programování #react #learning

Elementy formátu HTML pracují trochu jinak než jiné prvky DOM v Reactu, protože elementy formulářů přirozeně udržují nějaký vnitřní stav. Například tento formulář ve formátu HTML přijímá jediné jméno:


<form>
  <label>
    Name:
    <input type="text" name="name" />
  </label>
  <input type="submit" value="Submit" />
</form>

Tento formulář má výchozí chování formuláře HTML. V Reactu, ve většině případů je vhodné mít funkci JavaScriptu, která zpracovává odeslání formuláře, a má přístup k údajům, které uživatel zadal do formuláře. Standardní způsob, jak toho dosáhnout, je technika s názvem "řízené komponenty".

Řízené komponenty

V HTML se formátují prvky, jako < input > je < textarea> , a < select > typicky si udržují svůj vlastní stav a aktualizují ho na základě zadání uživatele. V Reactu je stav měnitelného stavu obvykle držen ve vlastnictví stavu komponent a aktualizován pouze setState().

Můžeme je spojit tím, že stav Reactu je "jediným zdrojem pravdy". Pak součást Reactu, která vykresluje formulář, také řídí, co se v této podobě děje na následném zadání uživatele. Prvek elementu input, jehož hodnota je tímto způsobem řízena Reactem, se nazývá "řízená komponenta".

Například pokud chceme, aby předchozí příklad přihlašoval název, můžeme napsat formulář jako řízenou komponentu:

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

Vzhledem k tomu, že atribut value je nastaven na náš prvek formuláře, zobrazí se vždy hodnota this.state.value, takže stav Reactu je zdrojem pravdy. Protože handleChange běží po každém stisknutí klávesy a aktualizuje stav Reactu, zobrazovaná hodnota se aktualizuje jako uživatelské typy.

S řízenou komponentou bude mít každá mutace stavu přidruženou funkci obsluhy. Díky tomu je snadné změnit nebo ověřit vstup uživatele. Pokud bychom například chtěli prosadit, aby tato jména byla napsána se všemi velkými písmeny, mohli bychom psát handleChangejako:

handleChange(event) {
  this.setState({value: event.target.value.toUpperCase()});
}

Element Textarea

V HTML element < textarea > je definován jeho text jako potomek:

<textarea>
  Hello there, this is some text in a text area
</textarea>

V Reactu se v elementu < textarea > místo toho používá atribut value. Tímto způsobem může < textarea > být podobná jednořádkovým formulářovým prvkům s jedním vstupem:

class EssayForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: 'Please write an essay about your favorite DOM element.'
    };

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('An essay was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Essay:
          <textarea value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

Všimněte si, že this.state.value je inicializován v konstruktoru, takže textová oblast začíná nějakým textem.

Element Select

V HTML tvoří < select > rozbalovací seznam. Například tento HTML vytvoří rozbalovací seznam příchutí:

<select>
  <option value="grapefruit">Grapefruit</option>
  <option value="lime">Lime</option>
  <option selected value="coconut">Coconut</option>
  <option value="mango">Mango</option>
</select>

Všimněte si, že volba Coconut je zpočátku vybrána díky atributu selected. React namísto použití tohoto atributu selected používá atribut value na kořenovém select tagu. To je výhodnější v řízené komponentě, protože je třeba ji pouze aktualizovat na jednom místě. Například:

class FlavorForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: 'coconut'};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('Your favorite flavor is: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Pick your favorite flavor:
          <select value={this.state.value} onChange={this.handleChange}>
            <option value="grapefruit">Grapefruit</option>
            <option value="lime">Lime</option>
            <option value="coconut">Coconut</option>
            <option value="mango">Mango</option>
          </select>
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

Celkově to dělá to tak, že < input type="text" >< textarea > < select > všichni pracují velmi podobně - všichni přijmout atribut value, který můžete použít k implementaci kontrolované položky.

Poznámka:
Do atributu value můžete předat pole, které vám umožní vybrat v select tagu několik možností:

<select multiple={true} value={['B', 'C']}>

Element File

V jazyce HTML < input type="file" > umožňuje uživateli vybrat jeden nebo více souborů z úložiště zařízení, které mají být nahrány na server nebo manipulovány pomocí jazyka JavaScript pomocí File API.

<input type="file" />

Protože je jeho hodnota pouze pro čtení, je to nekontrolovaná součást v Reactu.

Manipulace s více vstupy

Když potřebujete ovládat více řízených input prvků, můžete přidat atribut name a nechat funkci obsluhy vybrat, co dělat na základě hodnoty event.target.name.

Například:

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      numberOfGuests: 2
    };

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

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

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

  render() {
    return (
      <form>
        <label>
          Is going:
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          Number of guests:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
        </label>
      </form>
    );
  }
}

Všimněte si, jak jsme použili syntaxi názvů vlastností vypočteného parametrem ES6 k aktualizaci stavového klíče odpovídající danému zadanému názvu:

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

Je ekvivalentní tomuto kódu ES5:

var partialState = {};
partialState[name] = value;
this.setState(partialState);

Kontrolované Input s Null hodnotou

Určení hodnoty prop na řízené komponentě zabraňuje uživateli měnit vstup, pokud si to nepřejete. Pokud jste zadali hodnotu, value ale vstup je stále upravitelný, můžete se nechtěně nastavit value na hodnotu undefined nebo null.

Následující kód to demonstruje. (Vstup je nejprve zablokován, ale po krátkém zpoždění se dá upravovat.)

ReactDOM.render(<input value="hi" />, mountNode);

setTimeout(function() {
  ReactDOM.render(<input value={null} />, mountNode);
}, 1000);

Alternativy k řízeným komponentám

Někdy může být zdlouhavé používat řízené komponenty, protože musíte zapisovat obsluhu události pro každý způsob, jakým se data mohou měnit a průchod všech vstupních stavů prostřednictvím komponenty React. To může být obzvlášť nepříjemné, když převádíte existující kódovou bázi na React nebo integrujete aplikaci React s knihovnou bez Reactu. V těchto situacích byste se měli podívat na neřízené komponenety, alternativní techniku ​​pro implementaci vstupních formulářů.