2017-08-25 4 views
0

Reagieren (von create-react-app) mit MobX. Verwenden von Axios für asynchrone Back-End-API-AufrufeRefactoring bricht Anfangszustand

Dieser Code funktioniert. Der Anfangszustand (Array von Problemen) wird aufgefüllt, und die Webseite, auf der diese Komponente präsentiert wird, wird mit dem ursprünglichen Inhalt aus dem Status gerendert.

import { observable, computed, autorun, reaction } from 'mobx' 
import axios from 'axios' 

class IssuesStore { 
    @observable issues = [] 

    constructor() { 
    autorun(() => console.log("Autorun:" + this.buildIssues)) 

    reaction(
    () => this.issues, 
     issues => console.log("Reaction: " + issues.join(", ")) 
    ) 
    } 

    getIssues(data) { 
    return data.map((issue) => ({title: issue.name, url: issue.url, labels: issue.labels})) 
    } 

    @computed get buildIssues() { 
    const authToken = 'token ' + process.env.REACT_APP_GH_OAUTH_TOKEN 

    axios.get(`https://api.github.com/repos/${process.env.REACT_APP_GH_USER}/gh-issues-app/issues`, 
        { 'headers': {'Authorization': authToken} }) 
     .then(response => { 
     console.log(response) 
     this.issues = this.getIssues(response.data) 
     return this.issues 
     }) 
     .catch(function(response) { 
     console.log(response) 
     }) 
    } 
} 

export default IssuesStore 

In einem Versuch API-Aufruf Versprechen von einzelnen Komponenten und speichert zu trennen, zog ich den axios Anruf in eine separate JS-Datei aus, als eine Sammlung von Funktionen:

import axios from 'axios' 

const authToken = 'token ' + process.env.REACT_APP_GH_OAUTH_TOKEN 

export function loadIssues() { 
    return this.apiPromise(
    `https://api.github.com/repos/${process.env.REACT_APP_GH_USER}/gh-issues-app/issues`, 
    { 'headers': {'Authorization': authToken} } 
) 
} 

export function apiPromise(endpoint, options) { 
    return axios.get(endpoint, options) 
     .then((response) => { 
     // console.log("response: " + JSON.stringify(response, null, 2)) 
     return response.data.map((issue) => ({title: issue.name, url: issue.url, labels: issue.labels})) 
     }) 
     .catch(function(response) { 
     console.log(response) 
     }) 
} 

Nun, mein Speicher sieht wie folgt aus:

import { observable, computed, autorun, reaction } from 'mobx' 
import * as github from '../api/github' 

class IssuesStore { 
    @observable issues = [] 


    constructor() { 
    autorun(() => console.log("Autorun:" + this.buildIssues)) 

    reaction(
    () => this.issues, 
     issues => console.log("Reaction: " + issues.join(", ")) 
    ) 
    } 

    @computed get buildIssues() { 
    this.issues = github.loadIssues().data 
    return this.issues 
    } 
} 

export default IssuesStore 

Viel kleiner ... aber die Webseite nun einen Fehler wirft, weil es jetzt den Anfangszustand issues alssieht 0 beim ersten Rendern.

Uncaught TypeError: Cannot read property 'map' of undefined

Das Versprechen erfolgreich später vervollständigt (wie es sein sollte), aber dann ist es zu spät. Sicher, ich kann ein paar null Checks in meinen Rendering-Komponenten einrichten, um .map oder andere solche Funktionen nicht auf leeren oder noch nicht definierten Variablen laufen zu lassen.

Aber warum funktioniert der Code ohne anfängliche Renderfehler vor dem Refactoring, und nicht nach? Ich dachte, das Refactoring würde den gleichen Logikfluss beibehalten, aber ich muss etwas übersehen haben.

Antwort

1

In Ihrem Refactoring Version

github.loadIssues().data

weil dieses Versprechen die Daten Eigenschaft wird immer undefiniert werden immer undefiniert.

In der ursprünglichen Version, this.issues wurde nur einmal Daten aus der API zurückgegeben, so dass die einzigen Werte, die es jemals festgelegt wurde, waren der Anfangswert [] und das gefüllte Array von der API-Antwort.

In Ihrem sind die drei Zustände [] -> undefined -> und das gefüllte Array.

buildIssues sollte wie folgt aussehen:

@computed get buildIssues() { 
    github.loadIssues().then((data) => { 
     this.issues = data 
    }).catch((err) => { 
     // handle err. 
    }) 
} 
+0

Dank! Hat funktioniert. Mein Verständnis von Versprechungen war nicht gut genug, um zu verstehen, warum ich ein anderes '.then()' auf dem zurückgegebenen Versprechen brauchte, um meine Daten zu bekommen. Ich nahm an, dass das '' then() ', das in der Versprechung selbst definiert wurde, genug war, um zu holen, was ich innerhalb der Antwort brauchte. – changingrainbows