重构打破了初始状态

时间:2017-08-25 19:14:09

标签: javascript reactjs axios mobx-react

与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调用承诺,我将axios调用作为函数集合拉出到一个单独的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的初始状态视为undefined

Uncaught TypeError: Cannot read property 'map' of undefined

承诺稍后成功完成(应该如此),但到那时为时已晚。当然,我可以在渲染组件中设置一些null检查,以便在空或尚未定义的变量上运行.map或其他此类函数。

但为什么代码在重构之前没有初始渲染错误,而不是在之后呢?我认为重构有效地保持了相同的逻辑流程,但我必须遗漏一些东西?

1 个答案:

答案 0 :(得分:1)

在您的重构版本中

github.loadIssues().data

始终是未定义的,因为Promise上的数据属性将始终未定义。

在原始版本中,只有在从api返回数据时才设置this.issues,因此它设置的唯一值是初始值[]和来自api响应的填充数组。 / p>

在你的情况下,这三个州是[] - > undefined - >和填充的阵列。

buildIssues应该是这样的:

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