Two-Way-Databinding mit React

Von Haus aus kann React nur One-Way-Databinding, d.h. das Update des Models muss manuell vorgenommen werden (typischweise per onChange-Handler).

Gerade bei größeren Formularen, bei denen das Datenmodell 1:1 auch persistiert wird, entsteht dadurch viel Boiler-Plate-Code.

Ich stelle hier ein Beispiel für eine Eingabekomponente mit Two-Way-Databinding vor, die automatisch das Modell updated. Bei einem Update des Modells in der Parent-Komponente (z.B. nach dem Laden der Daten) wird die Referenz innerhalb der Komponente aktualisiert.

class LabeledInput extends Component {
  constructor(props) {
    super(props);
    
    this.state = { value: props.value };
    this.id = props.id;
    if (!this.state.value[this.id]) {
      this.state.value[this.id] = "";
    }
    this.handleChange = this.handleChange.bind(this);
    this.label = props.label;
    this.size = props.size ?? 40;
    this.styleClass = props.styleClass;
  }
  handleChange(e) {
    this.state.value[this.id] = e.target.value;
    this.setState({});
  }
  static getDerivedStateFromProps(props, state) {
    if (props.value !== state.value) {
      return {value: props.value};
    }
    return null;
  }
  render() {
    return (
        <div className={this.styleClass + " p-field"}>
          <label htmlFor={this.state.value.id + this.id} className="p-d-block">{this.label}</label>
          <input type="text" id={this.state.value.id + this.id} className="p-d-block" size={this.size}
              value={this.state.value[this.id]} onChange={this.handleChange} />
        </div>);
  }
}

Verwendet werden kann die Komponente wie folgt:

export class CustomerPage extends Component {
  constructor(props) {
    super(props);
    this.state = { model: { } };
    this.persist = this.persist.bind(this);
  }
  componentDidMount() {
    axios.get('/customer')
    .then(response => response.data)
    .then(model=> this.setState({ model}));
  }

  persist(e) {
    axios.post('/customer', this.state.model);
  }
  render(){
    return (
      <div>
        <LabeledInput id="name" label="Name" value={this.state.model}
 />
        <LabeledInput id="email" label="E-Mail-Adresse" value={this.state.model}
 />
        <LabeledInput id="telefon" label="Telefonnummer" value={this.state.model}
 />
        <button onClick={this.persist}>Speichern</button>
      </div>);
  }
}

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert