Réagissez (à partir de create-react-app) avec MobX. Utilisation d'axios pour les appels d'API backend asynchrones.Le refactoring rompt l'état initial
Ce code fonctionne. L'état initial (tableau de problèmes) est rempli, et la page Web présentant ce composant est rendue avec le contenu initial de l'état.
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
Pour tenter de séparer les promesses d'invocation de l'API à partir de composants individuels et les magasins, j'ai retiré l'appel Axios dans un fichier js séparé, comme une collection de fonctions:
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)
})
}
Maintenant, mon magasin ressemble à ceci:
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
Beaucoup plus petit ... mais la page Web lance maintenant une erreur parce qu'il voit maintenant l'état initial de issues
comme undefined
sur le premier rendu.
Uncaught TypeError: Cannot read property 'map' of undefined
La promesse vient compléter plus tard avec succès (comme il se doit), mais il est alors trop tard. Bien sûr, je peux configurer quelques contrôles null
dans mes composants de rendu pour ne pas exécuter .map
ou d'autres fonctions similaires sur des variables vides ou non encore définies.
Mais pourquoi le code fonctionne-t-il sans erreurs de rendu initial avant le refactoring, et non après? Je pensais que le refactoring maintenait effectivement le même flux logique, mais je dois manquer quelque chose?
Merci! Travaillé. Ma compréhension des promesses n'était pas assez bonne pour comprendre pourquoi j'avais besoin d'un autre '.then()' sur la promesse retournée pour obtenir mes données. J'ai supposé que le '.then()' défini dans la promesse elle-même était suffisant pour aller chercher ce dont j'avais besoin dans la réponse. – changingrainbows