So greifen Sie in React auf den Status eines Kindes zu

Lesezeit: 14 Minuten

So greifen Sie in React auf den Status eines Kindes
Zippo

Ich habe folgende Struktur:

FormEditor – Enthält mehrere Instanzen von FieldEditor
FieldEditor – bearbeitet ein Feld des Formulars und speichert verschiedene Werte darüber in seinem Zustand

Wenn im FormEditor auf eine Schaltfläche geklickt wird, möchte ich in der Lage sein, Informationen über die Felder von allen zu sammeln FieldEditor Komponenten, Informationen, die sich in ihrem Zustand befinden, und alles in FormEditor.

Ich habe überlegt, die Informationen über die Felder außerhalb von zu speichern FieldEditor‘s Zustand und fügen Sie es ein FormEditorstattdessen den Zustand von . Allerdings würde das erfordern FormEditor jedem seiner zuzuhören FieldEditor Komponenten, wenn sie sich ändern und ihre Informationen in ihrem Zustand speichern.

Kann ich stattdessen nicht einfach auf den Status der Kinder zugreifen? Ist es optimal?

  • „Kann ich nicht stattdessen einfach auf den Kinderstatus zugreifen? Ist das ideal?“ Nein. Staat ist etwas Inneres und sollte nicht nach außen dringen. Sie könnten Zugriffsmethoden für Ihre Komponente implementieren, aber selbst das ist nicht ideal.

    – Felix Klinge

    9. Januar 15 um 16:55 Uhr

  • @FelixKling Dann schlagen Sie vor, dass der ideale Weg für die Kommunikation zwischen Kind und Eltern nur Ereignisse sind?

    – Zippo

    9. Januar 15 um 18:37 Uhr

  • Ja, Ereignisse sind eine Möglichkeit. Oder haben Sie einen Datenfluss in eine Richtung, wie Flux fördert: facebook.github.io/flux

    – Felix Klinge

    9. Januar 15 um 18:40 Uhr

  • Wenn Sie nicht verwenden werden FieldEditors separat und speichern ihren Zustand in FormEditor hört sich gut an. Wenn dies der Fall ist, Ihre FieldEditor Instanzen werden basierend auf gerendert props von ihrem Formulareditor übergeben, nicht von ihrem state. Ein komplexerer, aber flexiblerer Weg wäre, einen Serialisierer zu erstellen, der alle untergeordneten Container durchgeht und alle findet FormEditor Instanzen zwischen ihnen und serialisiert sie in ein JSON-Objekt. Das JSON-Objekt kann optional verschachtelt werden (mehr als eine Ebene), basierend auf den Verschachtelungsebenen der Instanzen im Formulareditor.

    – Meglio

    24. Januar 16 um 13:03 Uhr


  • Ich denke, die React Docs „Staat anheben“ ist wahrscheinlich die reaktionsschnellste Art, dies zu tun

    – icc97

    11. Mai 17 um 14:08 Uhr

So greifen Sie in React auf den Status eines Kindes
Martoid Prime

Bevor ich näher darauf eingehe, wie Sie auf den Status einer untergeordneten Komponente zugreifen können, lesen Sie bitte die Antwort von Markus-ipse bezüglich einer besseren Lösung für dieses spezielle Szenario.

Wenn Sie tatsächlich auf den Zustand der Kinder einer Komponente zugreifen möchten, können Sie eine Eigenschaft namens zuweisen ref zu jedem Kind. Es gibt jetzt zwei Möglichkeiten, Referenzen zu implementieren: Using React.createRef() und Callback-Referenzen.

Verwenden React.createRef()

Dies ist derzeit die empfohlene Methode zur Verwendung von Referenzen ab React 16.3 (siehe die Dokumentation für mehr Informationen). Wenn Sie eine frühere Version verwenden, finden Sie unten Informationen zu Callback-Referenzen.

Sie müssen im Konstruktor Ihrer übergeordneten Komponente eine neue Referenz erstellen und diese dann über die einem untergeordneten Element zuweisen ref Attribut.

class FormEditor extends React.Component {
  constructor(props) {
    super(props);
    this.FieldEditor1 = React.createRef();
  }
  render() {
    return <FieldEditor ref={this.FieldEditor1} />;
  }
}

Um auf diese Art von Referenz zuzugreifen, müssen Sie Folgendes verwenden:

const currentFieldEditor1 = this.FieldEditor1.current;

Dadurch wird eine Instanz der bereitgestellten Komponente zurückgegeben, die Sie dann verwenden können currentFieldEditor1.state auf den Staat zugreifen.

Nur eine kurze Anmerkung, um zu sagen, dass, wenn Sie diese Referenzen auf einem DOM-Knoten anstelle einer Komponente (z <div ref={this.divRef} />) dann this.divRef.current gibt das zugrunde liegende DOM-Element anstelle einer Komponenteninstanz zurück.

Rückruf-Ref

Diese Eigenschaft akzeptiert eine Callback-Funktion, der ein Verweis auf die angefügte Komponente übergeben wird. Dieser Callback wird unmittelbar nach dem Mounten oder Unmounten der Komponente ausgeführt.

Beispielsweise:

<FieldEditor
    ref={(fieldEditor1) => {this.fieldEditor1 = fieldEditor1;}
    {...props}
/>

In diesen Beispielen wird die Referenz auf der übergeordneten Komponente gespeichert. Um diese Komponente in Ihrem Code aufzurufen, können Sie Folgendes verwenden:

this.fieldEditor1

und dann verwenden this.fieldEditor1.state den Staat zu bekommen.

Beachten Sie Folgendes: Stellen Sie sicher, dass Ihre untergeordnete Komponente gerendert wurde, bevor Sie versuchen, darauf zuzugreifen ^_^

Wenn Sie diese Referenzen wie oben auf einem DOM-Knoten anstelle einer Komponente verwenden (z <div ref={(divRef) => {this.myDiv = divRef;}} />) dann this.divRef gibt das zugrunde liegende DOM-Element anstelle einer Komponenteninstanz zurück.

Weitere Informationen

Wenn Sie mehr über die Eigenschaft ref von React erfahren möchten, lesen Sie weiter diese Seite von Facebook.

Stellen Sie sicher, dass Sie die “Refs nicht überbeanspruchen” Abschnitt, der besagt, dass Sie das des Kindes nicht verwenden sollten state um „Dinge geschehen zu lassen“.

  • Auch ein netter kleiner Leckerbissen, von dem aus man Funktionen aufrufen kann this.refs.yourComponentNameHere. Ich fand es nützlich, um den Status über Funktionen zu ändern. Beispiel: this.refs.textInputField.clearInput();

    – Dylan Pierce

    9. September 15 um 14:19 Uhr


  • Achtung (aus den Dokumenten): Refs sind eine großartige Möglichkeit, eine Nachricht auf eine Weise an eine bestimmte untergeordnete Instanz zu senden, die über das Streamen von Reactive umständlich wäre props und state. Sie sollten jedoch nicht Ihre bevorzugte Abstraktion für den Datenfluss durch Ihre Anwendung sein. Verwenden Sie standardmäßig den reaktiven Datenfluss und speichern Sie refs für Anwendungsfälle, die von Natur aus nicht reaktiv sind.

    – Lynne

    20. Juli 16 um 12:28 Uhr

  • Ich bekomme nur den Zustand, der im Konstruktor definiert wurde (nicht aktueller Zustand)

    – Vlado Pandžić

    21. Oktober 16 um 11:12 Uhr

  • Die Verwendung von Refs wird jetzt als Verwendung von ‘Unkontrollierte Komponenten‘ mit der Empfehlung, ‘Controlled Components’ zu verwenden

    – icc97

    11. Mai 17 um 23:03 Uhr

  • Ist dies möglich, wenn die untergeordnete Komponente ein Redux ist connected Komponente?

    – jmancherje

    20. März ’18 um 19:50 Uhr

1643312720 952 So greifen Sie in React auf den Status eines Kindes
Markus-ipse

Wenn Sie bereits einen onChange-Handler für die einzelnen FieldEditors haben, verstehe ich nicht, warum Sie den Status nicht einfach in die FormEditor-Komponente verschieben und von dort einfach einen Callback an die FieldEditors weitergeben können, die den übergeordneten Status aktualisieren. Das scheint mir ein eher reaktiver Weg zu sein.

Etwas in der Richtung vielleicht:

const FieldEditor = ({ value, onChange, id }) => {
  const handleChange = event => {
    const text = event.target.value;
    onChange(id, text);
  };

  return (
    <div className="field-editor">
      <input onChange={handleChange} value={value} />
    </div>
  );
};

const FormEditor = props => {
  const [values, setValues] = useState({});
  const handleFieldChange = (fieldId, value) => {
    setValues({ ...values, [fieldId]: value });
  };

  const fields = props.fields.map(field => (
    <FieldEditor
      key={field}
      id={field}
      onChange={handleFieldChange}
      value={values[field]}
    />
  ));

  return (
    <div>
      {fields}
      <pre>{JSON.stringify(values, null, 2)}</pre>
    </div>
  );
};

// To add the ability to dynamically add/remove fields, keep the list in state
const App = () => {
  const fields = ["field1", "field2", "anotherField"];

  return <FormEditor fields={fields} />;
};

Original – Pre-Hooks-Version:

class FieldEditor extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    const text = event.target.value;
    this.props.onChange(this.props.id, text);
  }

  render() {
    return (
      <div className="field-editor">
        <input onChange={this.handleChange} value={this.props.value} />
      </div>
    );
  }
}

class FormEditor extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};

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

  handleFieldChange(fieldId, value) {
    this.setState({ [fieldId]: value });
  }

  render() {
    const fields = this.props.fields.map(field => (
      <FieldEditor
        key={field}
        id={field}
        onChange={this.handleFieldChange}
        value={this.state[field]}
      />
    ));

    return (
      <div>
        {fields}
        <div>{JSON.stringify(this.state)}</div>
      </div>
    );
  }
}

// Convert to a class component and add the ability to dynamically add/remove fields by having it in state
const App = () => {
  const fields = ["field1", "field2", "anotherField"];

  return <FormEditor fields={fields} />;
};

ReactDOM.render(<App />, document.body);

  • Dies ist nützlich für onChange, aber nicht so sehr für onSubmit.

    – 190290000 Rubel Mann

    26. Juli 17 um 13:21 Uhr

  • @190290000RubleMan Ich bin mir nicht sicher, was Sie meinen, aber da die onChange-Handler für die einzelnen Felder sicherstellen, dass Sie immer die vollständigen Formulardaten in Ihrem Zustand in Ihrer FormEditor-Komponente verfügbar haben, würde Ihr onSubmit nur so etwas wie enthalten myAPI.SaveStuff(this.state);. Wenn du ein bisschen mehr ausführst, kann ich dir vielleicht eine bessere Antwort geben 🙂

    – Markus-ipse

    26. Juli 17 um 13:31 Uhr

  • Angenommen, ich habe ein Formular mit 3 Feldern unterschiedlichen Typs, jedes mit seiner eigenen Validierung. Ich möchte jeden von ihnen vor dem Absenden validieren. Wenn die Validierung fehlschlägt, sollte jedes fehlerhafte Feld neu gerendert werden. Ich habe nicht herausgefunden, wie dies mit Ihrer vorgeschlagenen Lösung zu tun ist, aber vielleicht gibt es einen Weg!

    – 190290000 Rubel Mann

    26. Juli 17 um 13:40 Uhr

  • @ 190290000RubleMan Scheint ein anderer Fall zu sein als die ursprüngliche Frage. Öffnen Sie eine neue Frage mit mehr Details und vielleicht etwas Beispielcode, und ich kann später nachsehen 🙂

    – Markus-ipse

    26. Juli 17 um 13:53 Uhr

  • Möglicherweise finden Sie diese Antwort nützlich: Sie verwendet Status-Hooks, sie behandelt, wo der Status erstellt werden soll, wie das erneute Rendern des Formulars bei jedem Tastendruck vermieden wird, wie die Feldvalidierung durchgeführt wird usw.

    – Andreas

    21. November 19 um 0:21 Uhr

1643312720 134 So greifen Sie in React auf den Status eines Kindes
Mauricio Avendaño

Versuchen Sie, wie in den vorherigen Antworten angegeben, den Status in eine oberste Komponente zu verschieben und den Status durch Rückrufe zu ändern, die an die untergeordneten Elemente weitergegeben werden.

Falls Sie wirklich auf einen untergeordneten Zustand zugreifen müssen, der als funktionale Komponente (Hooks) deklariert ist, können Sie a deklarieren Ref in der übergeordneten Komponente und übergeben Sie sie dann als a Ref Attribut für das Kind, aber Sie müssen verwenden React.forwardRef und dann der Haken useImperativeHandle um eine Funktion zu deklarieren, die Sie in der übergeordneten Komponente aufrufen können.

Schauen Sie sich das folgende Beispiel an:

const Parent = () => {
    const myRef = useRef();
    return <Child ref={myRef} />;
}

const Child = React.forwardRef((props, ref) => {
    const [myState, setMyState] = useState('This is my state!');
    useImperativeHandle(ref, () => ({getMyState: () => {return myState}}), [myState]);
})

Dann sollten Sie in der Lage sein, myState in der Parent-Komponente abzurufen, indem Sie Folgendes aufrufen:

myRef.current.getMyState();

  • Das ist fantastisch. Ich mag fast jedes Child-to-Eltern-State-Sharing-Muster nicht, das ist großartig. Ich weiß nicht, wie lange React Klassen über Hooks empfehlen kann. Haken sind sehr schnell.

    – Sternenkiesel

    3. September 2020 um 20:18 Uhr

  • Wenn ich anrufe ref.current.getMyState() innerhalb des DOM führt dies zu einem Fehler ref.current.getMyState is not a function, da die Komponente noch nicht gebaut wurde. Wenn man also den Staat braucht, um das DOM zu bauen, muss man leider eine andere Lösung wählen.

    – Sebastian

    31. Januar 21 um 12:36 Uhr

1643312720 276 So greifen Sie in React auf den Status eines Kindes
Josef Vidal

Es ist 2020 und viele von Ihnen werden hierher kommen und nach einer ähnlichen Lösung suchen, aber mit Haken (sie sind großartig!) und mit den neuesten Ansätzen in Bezug auf Code-Sauberkeit und Syntax.

Wie in früheren Antworten angegeben, besteht der beste Ansatz für diese Art von Problem darin, den Zustand außerhalb der untergeordneten Komponente zu halten fieldEditor. Sie können das auf mehrere Arten tun.

Am “komplexesten” ist ein globaler Kontext (Zustand), auf den sowohl Eltern als auch Kinder zugreifen und ihn ändern können. Es ist eine großartige Lösung, wenn sich Komponenten sehr tief in der Baumhierarchie befinden und es daher kostspielig ist, Requisiten in jeder Ebene zu senden.

In diesem Fall denke ich, dass es sich nicht lohnt, und ein einfacherer Ansatz wird uns die gewünschten Ergebnisse bringen, indem wir nur die Mächtigen verwenden React.useState().

Ein Ansatz mit einem React.useState()-Hook – viel einfacher als mit Klassenkomponenten

Wie gesagt, wir werden uns mit Änderungen befassen und die Daten unserer untergeordneten Komponente speichern fieldEditor bei unserem Elternteil fieldForm. Dazu senden wir eine Referenz an die Funktion, die die Änderungen behandelt und anwendet fieldForm zustand, das könntest du machen mit:

function FieldForm({ fields }) {
  const [fieldsValues, setFieldsValues] = React.useState({});
  const handleChange = (event, fieldId) => {
    let newFields = { ...fieldsValues };
    newFields[fieldId] = event.target.value;

    setFieldsValues(newFields);
  };

  return (
    <div>
      {fields.map(field => (
        <FieldEditor
          key={field}
          id={field}
          handleChange={handleChange}
          value={fieldsValues[field]}
        />
      ))}
      <div>{JSON.stringify(fieldsValues)}</div>
    </div>
  );
}

Beachten Sie, dass React.useState({}) gibt ein Array zurück, wobei Position 0 der beim Aufruf angegebene Wert ist (in diesem Fall ein leeres Objekt) und Position 1 die Referenz auf die Funktion ist, die den Wert ändert.

Jetzt mit der untergeordneten Komponente, FieldEditor, müssen Sie nicht einmal eine Funktion mit einer return-Anweisung erstellen. Eine magere Konstante mit einer Pfeilfunktion reicht aus!

const FieldEditor = ({ id, value, handleChange }) => (
  <div className="field-editor">
    <input onChange={event => handleChange(event, id)} value={value} />
  </div>
);

Aaaaund wir sind fertig, mehr nicht. Mit nur diesen beiden schlanken Funktionskomponenten haben wir unser Endziel “Zugang” zu unserem Kind FieldEditor Wert und zeigen Sie es in unserem Elternteil.

Sie können die akzeptierte Antwort von vor 5 Jahren überprüfen und sehen, wie Hooks den React-Code schlanker gemacht hat (um einiges!).

Ich hoffe, meine Antwort hilft Ihnen, mehr über Hooks zu lernen und zu verstehen, und wenn Sie a Arbeitsbeispiel hier ist es.

1643312720 783 So greifen Sie in React auf den Status eines Kindes
Dhana

Jetzt können Sie auf den Zustand des InputField zugreifen, der das untergeordnete Element von FormEditor ist.

Grundsätzlich erhalten wir bei jeder Änderung des Zustands des Eingabefelds (Kind) den Wert vom Ereignisobjekt und übergeben diesen Wert dann an das Elternteil, wo der Zustand im Elternteil festgelegt wird.

Auf Knopfdruck drucken wir einfach den Status der Eingang Felder.

Der entscheidende Punkt hier ist, dass wir die Requisiten verwenden, um das zu bekommen Eingabefelder id/value und auch um die Funktionen aufzurufen, die als Attribute auf der gesetzt sind Eingabefeld während wir das wiederverwendbare Kind generieren Eingang Felder.

class InputField extends React.Component{
  handleChange = (event)=> {
    const val = event.target.value;
    this.props.onChange(this.props.id , val);
  }

  render() {
    return(
      <div>
        <input type="text" onChange={this.handleChange} value={this.props.value}/>
        <br/><br/>
      </div>
    );
  }
}


class FormEditorParent extends React.Component {
  state = {};
  handleFieldChange = (inputFieldId , inputFieldValue) => {
    this.setState({[inputFieldId]:inputFieldValue});
  }
  // On a button click, simply get the state of the input field
  handleClick = ()=>{
    console.log(JSON.stringify(this.state));
  }

  render() {
    const fields = this.props.fields.map(field => (
      <InputField
        key={field}
        id={field}
        onChange={this.handleFieldChange}
        value={this.state[field]}
      />
    ));

    return (
      <div>
        <div>
          <button onClick={this.handleClick}>Click Me</button>
        </div>
        <div>
          {fields}
        </div>
      </div>
    );
  }
}

const App = () => {
  const fields = ["field1", "field2", "anotherField"];
  return <FormEditorParent fields={fields} />;
};

ReactDOM.render(<App/>, mountNode);

  • Ich bin mir nicht sicher, ob ich diesen positiv bewerten kann. Was erwähnen Sie hier, das nicht bereits von @Markus-ipse beantwortet wurde?

    – Alexander Vogel

    30. November 18 um 23:06 Uhr

  • OP stellte die Syntax unter Verwendung von Klassen anstelle von Funktionen bereit (wie in den besten Antworten angegeben), was impt ist, da die meisten Personen, die diese Frage lesen, auch nicht sicher wären, ob die korrekte Syntax korrekt wäre, wenn ich die beste Antwort in dieser Frage in die Verwendung von Klassen umwandeln würde. Tut mir leid, aber ich kenne nicht einmal den Namen der Klasse / Funktion

    – Petrus

    13. Januar 21 um 7:20 Uhr

  • Ich würde auch denken, dass mehr Variationen derselben Lösung gut für Leute sind, die sich brutal durch Reagieren zwingen: D

    – Petrus

    13. Januar 21 um 7:25 Uhr

1643312721 383 So greifen Sie in React auf den Status eines Kindes
Ayudh

Sie können auf den untergeordneten Zustand zugreifen, indem Sie einen Callback an die untergeordnete Komponente weiterleiten.

const Parent = () => {
  return (
    <Child onSubmit={(arg) => { 
             console.log('accessing child state from parent callback: ', arg) 
           }} 
    /> 
  )
}

const Child = ({onSubmit}) => {
    const [text, setText] = useState('');

    return (
      <>
        <input value={text} onChange={setText}>
        <button onClick={() => onSubmit(search)} />
      </>
    )
}

Wenn Sie jetzt auf die Schaltfläche in der untergeordneten Komponente klicken, führen Sie die von der übergeordneten Komponente übergebene Funktion aus und haben Zugriff auf die Zustandsvariablen der untergeordneten Komponente.

  • Ich bin mir nicht sicher, ob ich diesen positiv bewerten kann. Was erwähnen Sie hier, das nicht bereits von @Markus-ipse beantwortet wurde?

    – Alexander Vogel

    30. November 18 um 23:06 Uhr

  • OP stellte die Syntax unter Verwendung von Klassen anstelle von Funktionen bereit (wie in den besten Antworten angegeben), was impt ist, da die meisten Personen, die diese Frage lesen, auch nicht sicher wären, ob die korrekte Syntax korrekt wäre, wenn ich die beste Antwort in dieser Frage in die Verwendung von Klassen umwandeln würde. Tut mir leid, aber ich kenne nicht einmal den Namen der Klasse / Funktion

    – Petrus

    13. Januar 21 um 7:20 Uhr

  • Ich würde auch denken, dass mehr Variationen derselben Lösung gut für Leute sind, die sich brutal durch Reagieren zwingen: D

    – Petrus

    13. Januar 21 um 7:25 Uhr

.

664590cookie-checkSo greifen Sie in React auf den Status eines Kindes zu

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy