Reagiert auf asynchrones Rendern von Komponenten

82

Ich möchte meine Komponente rendern, nachdem meine Ajax-Anfrage abgeschlossen ist.

Unten sehen Sie meinen Code

var CategoriesSetup = React.createClass({

    render: function(){
        var rows = [];
        $.get('http://foobar.io/api/v1/listings/categories/').done(function (data) {
            $.each(data, function(index, element){
                rows.push(<OptionRow obj={element} />);
            });
           return (<Input type='select'>{rows}</Input>)

        })

    }
});

Aber ich bekomme den Fehler unten, weil ich Rendering innerhalb der erledigten Methode meiner Ajax-Anfrage zurückgeben.

Uncaught Error: Invariant Violation: CategoriesSetup.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object.

Gibt es eine Möglichkeit zu warten, bis meine Ajax-Anfrage beendet ist, bevor mit dem Rendern begonnen wird?

Thunfisch
quelle
3
Auch ein kleiner Nitpick, aber ein Datenabruf in einer render () - Routine ist keine wirklich gute Idee. Halten Sie render () beim Rendern und abstrahieren Sie den Rest. Außerdem möchten Sie diese Daten möglicherweise nur einmal abrufen, nicht jedes Mal, wenn die Komponente gerendert wird.
Phil Cooper

Antworten:

131

Es gibt zwei Möglichkeiten, dies zu handhaben. Welche Sie auswählen, hängt davon ab, welche Komponente die Daten und den Ladezustand besitzen soll.

  1. Verschieben Sie die Ajax-Anforderung in das übergeordnete Element und rendern Sie die Komponente unter bestimmten Bedingungen:

    var Parent = React.createClass({
      getInitialState: function() {
        return { data: null };
      },
    
      componentDidMount: function() {
        $.get('http://foobar.io/api/v1/listings/categories/').done(function(data) {
          this.setState({data: data});
        }.bind(this));
      },
    
      render: function() {
        if (this.state.data) {
          return <CategoriesSetup data={this.state.data} />;
        }
    
        return <div>Loading...</div>;
      }
    });
  2. Behalten Sie die Ajax-Anforderung in der Komponente bei und rendern Sie während des Ladens bedingt etwas anderes:

    var CategoriesSetup = React.createClass({
      getInitialState: function() {
        return { data: null };
      },
    
      componentDidMount: function() {
        $.get('http://foobar.io/api/v1/listings/categories/').done(function(data) {
          this.setState({data: data});
        }.bind(this));
      },
    
      render: function() {
        if (this.state.data) {
          return <Input type="select">{this.state.data.map(this.renderRow)}</Input>;
        }
    
        return <div>Loading...</div>;
      },
    
      renderRow: function(row) {
        return <OptionRow obj={row} />;
      }
    });
Michelle Tilley
quelle
6
Ich bin 2017 auf diese Antwort gestoßen. Bleiben diese beiden besten Lösungen immer noch die besten?
Dan
@Dan React rendert die Benutzeroberfläche basierend auf Requisiten und Status, sodass das Kernkonzept unverändert bleibt. Führen Sie die Ajax-Anforderung aus, legen Sie einen Status fest und rendern Sie etwas neu. Muster wie Komponenten höherer Ordnung sind jedoch populärer geworden und zeigen, wie man die Komplexität abstrahieren kann.
Michelle Tilley
1
if (this.state.data)sollte sein, if (this.state && this.state.data)weil manchmal Zustand null sein kann.
Timo
@ Timo Hm, in welchem ​​Fall wäre this.statedas null?
Michelle Tilley
5
@ Timo initialisieren den Zustand im Konstruktor
Louis
8

Das grundlegende Beispiel für das asynchrone Rendern von Komponenten ist unten aufgeführt:

import React                from 'react';
import ReactDOM             from 'react-dom';        
import PropTypes            from 'prop-types';

export default class YourComponent extends React.PureComponent {
    constructor(props){
        super(props);
        this.state = {
            data: null
        }       
    }

    componentDidMount(){
        const data = {
                optPost: 'userToStat01',
                message: 'We make a research of fetch'
            };
        const endpoint = 'http://example.com/api/phpGetPost.php';       
        const setState = this.setState.bind(this);      
        fetch(endpoint, {
            method: 'POST',
            body: JSON.stringify(data)
        })
        .then((resp) => resp.json())
        .then(function(response) {
            setState({data: response.message});
        });
    }

    render(){
        return (<div>
            {this.state.data === null ? 
                <div>Loading</div>
            :
                <div>{this.state.data}</div>
            }
        </div>);
    }
}
römisch
quelle