2016-07-19 10 views
0

Ich versuche herauszufinden, wie eine Komponente gefüllt/gerendert wird, wenn die Daten bereit sind? Im Wesentlichen habe ich ein Skript, das meinen Server abfragt, der Daten zurückgibt, dann parse ich es und mache es zu einer Sammlung mit den Eigenschaften, die ich brauche. Dann habe ich in einer anderen Datei die Reaktionskomponente, die nach dem Objekt sucht, aber sie läuft zur selben Zeit, so dass das Objekt nicht existiert, wenn die Komponente danach sucht.Wie rende ich eine Komponente, wenn die Daten bereit sind?

Ich bin mir nicht sicher, wie es weitergeht.

Dies ist meine Komponente:

let SliderTabs = React.createClass({ 
    getInitialState: function() { 
     return { items: [] } 
    }, 
    render: function() { 
     let listItems = this.props.items.map(function(item) { 
      return (
       <li key={item.title}> 
        <a href="#panel1">{item.title}</a> 
       </li> 
      ); 
     }); 

    return (
      <div className="something"> 
       <h3>Some content</h3> 
        <ul> 
         {listItems} 
        </ul> 
      </div> 
     ); 
    } 
}); 

ReactDOM.render(<SliderTabs items={home.data.slider} />,     
    document.getElementById('slider-tabs')); 

Wie ich meine Daten zu erhalten:

var home = home || {}; 

home = { 
    data: { 
    slider: [], 
    nav: [] 
    }, 
    get: function() { 

    var getListPromises = []; 

    $.each(home.lists, function(index, list) { 
     getListPromises[index] = $().SPServices.SPGetListItemsJson({ 
     listName: home.lists[index].name, 
     CAMLViewFields: home.lists[index].view, 
     mappingOverrides: home.lists[index].mapping 
     }) 
     getListPromises[index].list = home.lists[index].name; 
    }) 

    $.when.apply($, getListPromises).done(function() { 
     home.notice('Retrieved items') 
     home.process(getListPromises); 
    }) 
    }, 
    process: function(promiseArr) { 
    var dfd = jQuery.Deferred(); 

    $.map(promiseArr, function(promise) { 
     promise.then(function() { 
     var data = this.data; 
     var list = promise.list; 

     // IF navigation ELSE slider 
     if (list != home.lists[0].name) { 
      $.map(data, function(item) { 
      home.data.nav.push({ 
       title: item.title, 
       section: item.section, 
       tab: item.tab, 
       url: item.url.split(",")[0], 
       path: item.path.split("#")[1].split("_")[0] 
      }) 
      }) 
     } else { 
      $.map(data, function(item) { 
      home.data.slider.push({ 
       title: item.title, 
       url: item.url.split(",")[0], 
       path: item.path.split("#")[1] 
      }) 
      }) 
     } 
     }) 
    }) 

    console.log(JSON.stringify(home.data)) 
    dfd.resolve(); 
    return dfd.promise(); 
    } 
} 

$(function() { 
    home.get() 
}) 
+0

Haben Sie Redux überhaupt untersucht? Das ist der einfachste Weg, um den Überblick zu behalten und mit Daten zu arbeiten. – erichardson30

+0

Ich habe nicht wirklich, ich habe gerade angefangen, React heute anzusehen, also bin ich noch nicht allzu vertraut mit allem. – Batman

+0

Nachdem Sie mit den Daten fertig sind, verwenden Sie 'setState'. Sollte so einfach sein. Nicht in Redux tun. Es ist nicht wirklich notwendig für Anfänger. Und wie React immer erwähnt, sollte das Rendering eine Funktion von "Requisiten" (extern) + "Zustand" (intern) sein. – activatedgeek

Antwort

0

Sie sollten die Länge der Datenerhebung testen. Wenn die Sammlung leer ist, geben Sie einen Platzhalter (z. B. ein Laderad) zurück. In anderen Fällen können Sie die Datensammlung wie gewohnt anzeigen.

const SliderTabs = ({items}) => { 
    let listItems = <p>Loading data...</p> 

    if(items.length != 0) 
     listItems = items.map(item => 
      <li key={item.title}> 
       <a href="#panel1">{item.title}</a> 
      </li> 
     ) 

    return (
     <div className="something"> 
      <h3>Some content</h3> 
       <ul> 
        {listItems} 
       </ul> 
     </div> 
    ) 
} 

ReactDOM.render(
    <SliderTabs items={home.data.slider} />,     
    document.getElementById('slider-tabs') 
) 

habe ich die funktionelle Art und Weise verwenden, um eine Reaktion Komponente zu definieren, wie es der empfohlene Weg ist, wenn Sie nicht von einem Zustand, Refs oder Lifecycle methodes brauchen.

Wenn Sie dies in einer ES6-Klasse oder mit React.createCompnent (vermeiden) verwenden möchten, verwenden Sie einfach die Funktion als Render-Funktion. (Vergessen Sie nicht items Form die Requisiten zu extrahieren)


EDIT: Durch die neuen Antworten zu lesen, ich habe gemerkt, dass ich noch nicht vollständig beantwortet.

Wenn Sie möchten, dass die Ansicht aktualisiert wird, wenn die Daten geladen werden, müssen Sie etwas mehr Datenabrufcode integrieren. Ein grundlegendes Muster in React besteht darin, Ihre Komponenten im Wergentyp zu trennen: die Containerkomponente und die Darstellungskomponente.

Die Container werden sich nur um die Logik kümmern und die nützlichen Daten holen. Auf der anderen Seite zeigen die Präsentationskomponenten nur die vom Container angegebenen Daten an.

Hier ein kleines Beispiel: (try it on jsfidle)

Test-Dienstprogramme

var items = [{title: "cats"},{title: "dogs"}] 

//Test function faking a REST call by returning a Promise. 
const fakeRest =() => new Promise((resolve, reject) => 
    setTimeout(() => resolve(items), 2000) 
) 

Container Komponente

//The Container Component that will only fetch the data you want and then pass it to the more generic Presentational Component 
class SliderTabList extends React.Component { 
    constructor(props) { // 
    super(props) 
    //You should always give an initial state (if you use one of course) 
    this.state = { items : [] } 
    } 

    componentDidMount() { 
    fakeRest().then(
     items => this.setState({ items }) //Update the state. This will make react rerender the UI. 
    ) 
    } 

    render() { 
    //Better to handle the fact that the data is fetching here. 
    //This let the Presentational Component more generic and reusable 
    const {items} = this.state 
    return (
     items.length == 0 
     ? <p>Loading Data...</p> 
     : <List items={items} /> 
    ) 
    } 
} 

Präsentations Komponente

//The Presenational Component. It's called List because, in fact, you can reuse this component with other Container Component. Here is power of React. 
const List = ({items}) => { 
    //Prepare the rendering of all items 
    const listItems = items.map(item => 
     <li key={item.title}> 
     <a href="#panel1">{item.title}</a> 
     </li> 
    ) 

    //Simply render the list. 
    return (
     <div className="something"> 
     <h3>Some content</h3> 
      <ul> 
      {listItems} 
      </ul> 
     </div> 
    ) 
} 

den App Rendering

//Mount the Container Component. It doesn't need any props while he is handling his state itself 
ReactDOM.render(
    <SliderTabList />,     
    document.getElementById('slider-tabs') 
) 

Anstatt Überprüfung auf die Länge nicht 0 ist zu, Sie auch items zu null im Zustand initialisieren können, Abrufen von Daten von leer zu differenzieren zu können, Daten. Ein anderer üblicher Weg, um ein Flag zu setzen (ein Boolean in fetchingData int in den Zustand), um zu wissen, ob Daten abgerufen werden oder nicht.Aber in vielen Artikeln wird im Allgemeinen empfohlen, einen möglichst kleinen Zustand zu haben und dann alles zu berechnen, was man davon braucht. Also, hier suggest du dich nach der Länge oder der null.

+0

Wird es weiterhin überprüft? – Batman

+0

Ich habe dies in einer Geige versucht, sind eine grundlegende Implementierung ohne auf die Daten warten, funktioniert nicht. https://jsfiddle.net/69z2wepo/49604/ – Batman

+0

Sorry, ich habe vergessen, eine Klammer zu löschen: https://jsfiddle.net/69z2wepo/49615/ –

-2

Normalerweise würden Sie eine Antwort auf ein Ereignis OnLoad arrangieren, das "Feuer" wird, sobald die Daten geladen worden sind.

ich mit Emrys einverstanden, dass Ihr Code sollte auch zu testen, vorbereitet werden, ob die Daten noch verfügbar sind, und auf dem anfänglichen Unentschieden „etwas Vernünftiges zu tun“ (wenn es wahrscheinlich nicht). Aber nein, Sie würden dann nicht "abfragen", um zu sehen, ob die Daten angekommen sind:   Stattdessen arrangieren Sie, benachrichtigt zu werden, wenn das Ereignis ausgelöst wird. Zu dieser Zeit würden Sie (zum Beispiel) die UI-Komponenten neu zeichnen, um die Informationen widerzuspiegeln.

Ich verweise Sie sich bitte an die React Dokumentation genau zu sehen, wie diese Benachrichtigung erfolgt ...

0

Here ist die explaination der Art und Weise der Reaktion diese Art von Dingen zu tun, tl; dr - macht die Komponente sofort und entweder Ladeanzeige anzeigen, bis die Daten bereit sind, oder null von der render Methode zurückgeben.

+0

Der Link, den Sie gesendet haben, zeigt, wie es geht, wenn die Komponente selbst die Daten lädt, aber ich meine Daten erhalte und sie außerhalb von Reagieren speichert. – Batman

+0

Ich würde sagen, es ist effizienter, eine Komponente zuerst zu erstellen und Platzhalter für Ihre Daten darin zu lassen und sie zu füllen, sobald die Daten ankommen, anstatt zu warten, bis die Ajax-Anfrage beendet ist und erneut auf die Erstellung und Wiedergabe der Komponente zu warten denke, dass das Verhalten async sein sollte. – Igorsvee

1

Eine gängige Methode in React besteht darin, zu verfolgen, wann Daten abgerufen werden. Dies kann z.B. indem ein isFetching Feld in Ihrem Zustand:

// This would be your default state 
this.state = { 
    isFetching: false 
}; 

Dann, wenn Sie die Anfrage (vorzugsweise in componentDidMount) abfeuern setzen Sie isFetching auf true mit:

this.setState({ isFetching: true }); 

Und schließlich, wenn die Daten ankommen , können Sie es auf false gesetzt wieder:

this.setState({ isFetching: false }); 

nun in Ihrer Render Funktion können Sie etwas tun können:

render() { 
return (
    <div className="something"> 
     <h3>Some content</h3> 
     {this.state.isFetching ? <LoadingComponent /> : (
     <ul> 
      {listItems} 
     </ul> 
    )} 
    </div> 
) 
} 

Durch Zustand verwenden, müssen Sie entsprechend es keine Sorge über erzählen Sie Ihre Komponente etwas zu tun, sondern es reagieren auf Änderungen im Zustand und rendert.

Update:

Wenn Sie planen tatsächlich Reagieren mit, ich würde vorschlagen, dass Sie Ihren Ansatz ändern in das, was ich oben beschrieben habe (lesen Sie mehr in the React docs). Das heißt, bewegen Sie den Code, den Sie in Ihrer get Funktion haben, in die Funktion Ihrer React-Komponente componentDidMount. Wenn das nicht möglich ist, können Sie wahrscheinlich nur warten, bis Sie Ihre Daten erhalten haben:

.

+0

Wo setzt du 'this.state' und' setState'? Müsste nicht 'home.get()' den Zustand ändern? Ich bin mir nicht sicher, wie 'home.get()' das Flag für den Komponentenstatus ändern kann. Es sei denn, es ist global? – Batman

+0

Wenn Sie wirklich nicht wollen, dass die Daten mit React (ich würde vorschlagen, wenn möglich), dann können Sie nicht verwenden, was ich beschrieben habe. Siehe meine aktualisierte Antwort. – tobiasandersen

0

Legen Sie diese Daten in die übergeordnete Komponente laden, die die Requisiten Ihrer Komponente aktualisiert, während die Daten geladen werden.

Verwenden Sie Standardrequisiten anstelle des Standardstatus, da Sie in Ihrem Beispiel überhaupt keinen Status verwenden.Ersetzen Sie die ‚getInitialState‘ mit diesem:

getDefaultProps: function() { 
    return { 
     items: [] 
    }; 
    } 
0

bekam ich ein paar Antworten, aber ich war immer noch eine Menge Probleme, zu verstehen, wie zu erreichen, was ich bat um. Ich verstehe, dass ich die Daten mit den Komponenten abrufen sollte, aber ich weiß derzeit nicht genug über React, um das zu tun. Ich muß natürlich mehr Zeit damit verbringen, es zu lernen, aber jetzt war ich mit dieser:

Im Wesentlichen, habe ich die Eigenschaft ready zu mir nach Hause Objekt:

home.ready: false, 
home.init: function() { 
     // check if lists exist 
     home.check() 
     .then(home.get) 
     .then(function() { 
      home.ready = true; 
     }) 
    } 

Dann habe ich componentDidMount und setTimeout zu überprüfen, wenn die Daten bereit sind und die Ergebnisse an den this.state

let SliderTabs = React.createClass({ 
    getInitialState: function() { 
     return {items:[]} 
    }, 
    componentDidMount: function() { 
     let that = this; 

     function checkFlag() { 
      if(home.ready == false) { 
       window.setTimeout(checkFlag, 100); /* this checks the flag every 100 milliseconds*/ 
      } else { 
       that.setState({items: home.data.slider}) 
      } 
     } 
     checkFlag(); 
    }, 
    render: function() { 
     let listItems = this.state.items.map(function(item) { 
      return (
       <li key={item.title}> 
        <a href="#panel1">{item.title}</a> 
       </li> 
       ); 
     }); 

     return (
      <div className="something"> 
       <h3>Some content</h3> 
       <ul> 
        {listItems} 
       </ul> 
      </div> 
      ); 
    } 
}); 

ReactDOM.render(<SliderTabs/>,   
    document.getElementById('slider-tabs')); 

wohl nicht reagieren Art und Weise eingestellt, aber es scheint zu funktionieren.