简体   繁体   中英

Successive promise calls overriding return value

I have a React site and I've set up a component to display the current temperature as well as the current temperature 10 and 20 years ago. (I'm using DarkSky .)

The component looks like this (simplified):

class WeatherPreview extends React.Component {
  state = {
    weather: {},
    weatherTen: {},
    weatherTwenty: {}
  }

  getWeather = async (years) => {
    const targetDate = years ? moment().subtract(years, 'years') : null

    const basePath = 'http://localhost:3000'

    const res = targetDate ?
      await fetch(`${basePath}/api/weather?date=${targetDate}`) :
      await fetch(`${basePath}/api/weather`)

    const weather = await res.json()

    return weather
  }

  async componentDidMount() {
    const weather = await this.getWeather()
    const weatherTen = await this.getWeather(10)
    const weatherTwenty = await this.getWeather(20)

    this.setState({ weather, weatherTen, weatherTwenty })
  }

  render() {
    const { weather, weatherTen, weatherTwenty } = this.state

    return (
      <div>
        {weather.currently.temperature}°
        {weatherTen.currently.temperatureTen}°
        {weatherTwenty.currently.temperatureTwenty}°
      </div>
    )
  }
}

The API endpoint code looks like this (simplified):

const darkskyOptions = {
  latitude: 38.328732,
  longitude: -85.764771,
  language: 'en',
  units: 'us',
  exclude: ['minutely', 'hourly', 'daily', 'alerts', 'flags']
}

export default function handle(req, res) {
  const date = req.query.date || null

  if (!!date) {
    darkskyOptions.time = date
  }
  else {
    // Clear out time option if it's there
    // Or else it will mess up our current weather call
    delete darkskyOptions.time
  }

  const freshWeather = new Promise(resolve => resolve(
    darksky.options(darkskyOptions).get()
  ))

  freshWeather.then((newData) => {
    res.json(newData)
  }, (err) => {
    console.log('Error retrieving Dark Sky weather data.')
    console.log(err)
  })
}

When I refresh the page after a code change the correct data loads the first time:

90° 75° 72°

However, when I refresh the page after this initial load, the data for 20 years in the past replaces the current data.

72° 75° 72°

When I log things in the API endpoint code there is never anything that would indicate an error. The time property is never there for the current call, it always seems to be deleted, the correct options always seemed to be passed. Essentially the logic seems to check out.

But if I log weather and weatherTwenty in the component, weather is definitely holding the value of weatherTwenty .

Is there something wrong with my code pattern? When those asnyc await calls are made are they unique or can they get "crisscrossed" in their returns?

Problem is probably caused because you're mutating options and keep using it between requests. Try the following:

export default function handle(req, res) {
  const date = req.query.date || null
  //copy options and use that one
  const copyOptions = {...darkskyOptions};

  if (!!date) {
    copyOptions.time = date
  }
  else {
    // Clear out time option if it's there
    // Or else it will mess up our current weather call
    delete copyOptions.time
  }

  const freshWeather = new Promise(resolve => resolve(
    darksky.options(copyOptions).get()
  ))

  freshWeather.then((newData) => {
    res.json(newData)
  }, (err) => {
    console.log('Error retrieving Dark Sky weather data.')
    console.log(err)
  })
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM