2017-08-25 115 views
0

與MobX反應(來自create-react-app)。使用axios進行異步後端API調用。重構打破初始狀態

此代碼有效。初始狀態(問題陣列)已填充,呈現此組件的網頁呈現來自狀態的初始內容。

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 

在試圖分開各個組件和存儲API調用的承諾,我拿出了愛可信的呼叫到一個單獨的js文件,作爲函數的集合:

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) 
     }) 
} 

現在,我的商店看起來是這樣的:

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 

小得多......但由於它現在看到的issues作爲初始狀態的網頁現在拋出一個錯誤0在第一次渲染。

Uncaught TypeError: Cannot read property 'map' of undefined

的承諾成功完成以後(因爲它應該),但那時已經太晚了。當然,我可以在我的渲染組件中設置幾個null檢查,以便在空的或尚未定義的變量上不運行.map或其他此類函數。

但是爲什麼代碼在重構之前沒有初始渲染錯誤,而不是在之後工作?我認爲重構實際上保持了相同的邏輯流程,但我必須錯過什麼?

回答

1

在你的重構版本

github.loadIssues().data

總是將是不確定的,因爲這一承諾數據屬性將始終是不確定的。

在原始版本中,this.issues只有在從api返回數據時才設置,所以它唯一的值就是初始值[]和來自api響應的填充數組。

在你的這三個狀態是[] - > undefined - >和填充數組。

buildIssues應該是這個樣子:

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

謝謝!工作。我對承諾的理解不足以理解爲什麼我需要另一個'.then()'在返回的承諾來獲取我的數據。我認爲承諾中定義的'.then()'足以在響應中獲取我需要的內容。 – changingrainbows