Sortir une variable d'une Promise

a marqué ce sujet comme résolu.

Salut,

je suis en train de mettre en place un calendrier sur un site avec le module Big-Calendar de React. Pour cela je récupère la liste des évènements stockés dans la base de donnée en faisant un fetch sur l’API dans la fonction getEvents. Le problème c’est que je dois mettre le résultat de ce fetch dans une variable qui est accessible en dehors de la Promise (la variable events dans le code ci-dessous) pour pouvoir la passer en argument au calendrier.

J’ai lu pas mal de truc sur l’utilisation des Promise et le code asynchrone en JS mais j’arrive toujours pas à résoudre mon problème, donc je pense que je mis prends juste mal… :/

Le code est le suivant :

import React, { Fragment, useMemo } from 'react'
import PropTypes from 'prop-types'
import moment from 'moment'

import {
  Calendar,
  Views,
  DateLocalizer,
  momentLocalizer
} from 'react-big-calendar'

import DemoLink from './calendar_example/DemoLink.component.js'
//import events from './calendar_example/event'
import * as dates from './calendar_example/dates'

const mLocalizer = momentLocalizer(moment)

async function getEvents() {
    response = await fetch('/api/events')
        .then(
            result => {
                return result.json()
            },
            error => {
                console.error("Error getting the events: " + error)
            }
        )

    events = response.results

    addOneHour = d => {
        d.setHours(d.getHours() + 1)
        return d
    }

    let formatted_events = [] // Events formatted for BigCalendar
    for (e of events) {
        formatted_events.push(
            {
                id: e.id,
                title: e.name,
                desc: e.description,
                start: new Date(e.date),
                end: addOneHour(new Date(e.date))
            }
        )
    }

    return formatted_events
}

const ColoredDateCellWrapper = ({ children }) =>
  React.cloneElement(React.Children.only(children), {
    style: {
      backgroundColor: 'lightblue'
    }
  })

/**
 * We are defaulting the localizer here because we are using this same
 * example on the main 'About' page in Storybook
 */

export default function Basic ({
  localizer = mLocalizer,
  showDemoLink = true,
  ...props
}) {
  const { components, defaultDate, max, views } = useMemo(
    () => ({
      components: {
        timeSlotWrapper: ColoredDateCellWrapper
      },
      defaultDate: new Date(2015, 3, 1),
      max: dates.add(dates.endOf(new Date(2015, 17, 1), 'day'), -1, 'hours'),
      views: Object.keys(Views).map((k) => Views[k])
    }),
    []
  )

  return (
    <>
      <div className='height600' {...props}>
        <Calendar
          components={components}
          defaultDate={defaultDate}
          events={events}
          localizer={localizer}
          max={max}
          showMultiDayTimes
          step={60}
          views={views}
        />
      </div>
    </>
  )
}
Basic.propTypes = {
  localizer: PropTypes.instanceOf(DateLocalizer),
  showDemoLink: PropTypes.bool
}

Merci d’avance pour votre aide :)

PS : Je suis désolé, le titre du post est pourri mais je savais vraiment pas quoi mettre pour être explicite

+0 -0

Salut,

Attention avec le scope de tes variables : ici events n’est pas déclarée et risque donc d’entrer en conflit avec d’autres variables.

Tu utilises await donc tu devrait bien pouvoir récupérer le résultat de ta requête dans response : as-tu vérifié ce que ça contient ?

Pense bien à abuser de console.dir(var) voire de l’instruction debugger pour voir l’état de ton code à différentes étapes.

Attention avec le scope de tes variables : ici events n’est pas déclarée et risque donc d’entrer en conflit avec d’autres variables.

viki53

Oui, j’avais un peu trop bidouillé mon code pour tenté des trucs et j’ai oublié de remettre un truc propre

Tu utilises await donc tu devrait bien pouvoir récupérer le résultat de ta requête dans response : as-tu vérifié ce que ça contient ?

viki53 La response contient bien ce que je veux

En fait, c’est un peu bizarre, j’ai réécrit la fonction comme ça (le reste du code est inchangé) :

var events

async function getEvents() {
    response = await fetch('/api/events')
        .then(
            result => {
                return result.json()
            },
            error => {
                console.error("Error getting the events: " + error)
            }
        )

    raw_events = response.results

    console.log(raw_events)

    addOneHour = d => {
        d.setHours(d.getHours() + 1)
        return d
    }

    let formatted_events = [] // Events formatted for BigCalendar
    for (e of raw_events) {
        formatted_events.push(
            {
                id: e.id,
                title: e.name,
                desc: e.description,
                start: new Date(e.date),
                end: addOneHour(new Date(e.date))
            }
        )
    }

    events = formatted_events

    return formatted_events
}

getEvents()
console.dir(events)

Et quand je charge ma page j’obtiens l’erreur suivante :

Uncaught (in promise) ReferenceError: assignment to undeclared variable response
    _callee$ basic_calendar.jsx:21
    Babel 10
    getEvents basic_calendar.jsx:41
    <anonymous> basic_calendar.jsx:58
    jsx BigCalendar.bundle.js:699
    __webpack_require__ BigCalendar.bundle.js:5627
    <anonymous> calendar.js:4
    js BigCalendar.bundle.js:688
    __webpack_require__ BigCalendar.bundle.js:5627
    <anonymous> BigCalendar.bundle.js:5691
    <anonymous> BigCalendar.bundle.js:5693
basic_calendar.jsx:21:4

Et quand j’execute mon code depuis la console de Firefox, le console.dir(events) affiche undefined mais j’ai pas d’erreurs. Et si je refais un console.dir(events) à la main, ça m’affiche bien mon array mais ça, ça me semble être le comportement normal d’un code asynchrone, juste à la première execution, la fonction getEvents n’avait pas finit d’être executée.

+0 -0

Malheureusement ça ne marche pas :'( , j’obtiens l’erreur suivante :

Uncaught Error: Module parse failed: The top-level-await experiment is not enabled (set experiments.topLevelAwait: true to enabled it)

Il semblerait que React ne supporte pas les top level await :/ (cf. ce post)

+0 -0

Désolé, ça fait longtemps que j’ai pas répondu. :/

Néanmoins, j’ai eu une illumination sur ce qu’il fallait chercher pour résoudre mon problème en allant en cours. Du coup, normalement il faut utiliser le hook useAsync de React. J’ai juste pas pu tester parce que j’avais un problème avec Docker et j’ai pas eu trop le temps de travailler sur ce projet récemment.

Je reposterai un message si ça fonctionne bien mais normalement c’est bon.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte