重构打破初始状态
Refactoring breaks initial state
React(来自 create-react-app)与 MobX。使用 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
或其他类似的空变量或尚未定义的变量的函数。
但为什么代码在重构之前没有初始渲染错误,而重构之后却没有?我认为重构有效地保持了相同的逻辑流程,但我一定遗漏了什么?
在你的重构版本中
github.loadIssues().data
始终未定义,因为该 Promise 上的数据 属性 始终未定义。
在原始版本中,this.issues
仅在从 api 返回数据后设置,因此它设置的唯一值是初始值 [] 和填充数组来自 api 回复。
你这三个状态是[] -> undefined -> 和filled array
buildIssues
应该看起来像这样:
@computed get buildIssues() {
github.loadIssues().then((data) => {
this.issues = data
}).catch((err) => {
// handle err.
})
}
React(来自 create-react-app)与 MobX。使用 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
或其他类似的空变量或尚未定义的变量的函数。
但为什么代码在重构之前没有初始渲染错误,而重构之后却没有?我认为重构有效地保持了相同的逻辑流程,但我一定遗漏了什么?
在你的重构版本中
github.loadIssues().data
始终未定义,因为该 Promise 上的数据 属性 始终未定义。
在原始版本中,this.issues
仅在从 api 返回数据后设置,因此它设置的唯一值是初始值 [] 和填充数组来自 api 回复。
你这三个状态是[] -> undefined -> 和filled array
buildIssues
应该看起来像这样:
@computed get buildIssues() {
github.loadIssues().then((data) => {
this.issues = data
}).catch((err) => {
// handle err.
})
}