2017-08-25 44 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