Как установить состояние из одного вызова API и использовать данные для URL-адреса в следующем вызове API?

Мне нужны данные из вызова API 1 для добавления к URL-адресу вызова API 2. Данные из API 2 перейдут в URL-адрес для API 3. Я устанавливаю состояние для каждого запроса Axios, и оно не работает. Возврат неопределенного

componentDidMount() {
  // Get the IP adress of user
  axios
    .get('https://api.ipify.org?format=json')
    .then(res => {
      this.setState({
        ip: res.data.ip
      });
      console.info(`IP : ${this.state.ip}`);
    })
    .catch(err => console.info(err));

  // GET the coordinates of a location based on IP adress
  axios
    .get(
      'https://geo.ipify.org/api/v1?apiKey=YOUR_API_KEY&ipAddress=24.8.227.87'
    )
    .then(res => {
      this.setState({
        latitude: res.data.location.lat,
        longitude: res.data.location.lng
      });
      console.info(
        `Latitude: ${this.state.latitude}. Longitude: ${this.state.longitude}`
      );
    })
    .catch(err => console.info(err));

  // Make the API call on page load
  axios({
      method: 'get',
      url: `https://developers.zomato.com/api/v2.1/geocode?lat=39.6924553&lon=-105.0256318`,
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        Accept: 'application/json',
        'user-key': 'USER_KEY'
      }
    })
    .then(res => {
      const restaurantsNearMe = res.data.nearby_restaurants;

      this.setState({
        restaurants: restaurantsNearMe
      });

      // Pick out a random retaurant from what the API returns
      var randomRestaurant =
        restaurantsNearMe[
          Math.floor(Math.random() * restaurantsNearMe.length)
        ];

      // Select only the data that you want
      var finalResult = {
        name: randomRestaurant.restaurant.name,
        id: randomRestaurant.restaurant.id,
        rating: randomRestaurant.restaurant.user_rating.aggregate_rating,
        ratingColor: randomRestaurant.restaurant.user_rating.rating_color,
        address: randomRestaurant.restaurant.location.address,
        delivery: randomRestaurant.restaurant.is_delivering_now,
        typeOfFood: randomRestaurant.restaurant.cuisines
      };

      this.setState({
        restaurant: finalResult
      });
      console.info(this.state.restaurant);
    })
    .catch(err => console.info(err));
}

Проверьте цепочку промисов: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…. Это функция, которую вы ищете, и в статье MDN объясняется, почему некоторые фрагменты состояния не определены, когда кажется, что они не должны быть.

Jake Worth 31.05.2019 07:05
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
1
71
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

нужно иметь в виду, что this.setState не является синхронным. React объединяет несколько вызовов set state для повышения производительности рендеринга. Вот почему вы можете видеть undefined в console.info. Метод setState принимает обратный вызов в качестве второго параметра.

this.setState(newState, callbalck)

поэтому попробуйте войти в консоль обратного вызова и попробовать.

Я не знаю, как вы вызываете API, но попробуйте что-то вроде этого:

В componentDidMount вы можете сделать это:

async componentDidMount(){
  const resApiOne = await callFirstApi();
  this.setState({resApiOne});
  const resApiTwo = await callSecondApi(resApiOne);
  this.setState({resApiTwo});
}
Ответ принят как подходящий

Вам нужен callback в setState, а в этом callback нужно вызвать второго API и так далее. Проверьте это.

Это то, что вы хотите,

axios
    .get('https://api.ipify.org?format=json')
    .then(res => {
        this.setState({
            ip: res.data.ip
        }, () => {
            // GET the coordinates of a location based on IP adress
            axios
                .get(
                    'https://geo.ipify.org/api/v1?apiKey=YOUR_API_KEY&ipAddress=24.8.227.87'
                )
                .then(res => {
                    this.setState({
                        latitude: res.data.location.lat,
                        longitude: res.data.location.lng
                    }, () => {
                        // Make the API call on page load
                        axios({
                                method: 'get',
                                url: `https://developers.zomato.com/api/v2.1/geocode?lat=39.6924553&lon=-105.0256318`,
                                headers: {
                                    'Content-Type': 'application/x-www-form-urlencoded',
                                    Accept: 'application/json',
                                    'user-key': 'USER_KEY'
                                }
                            })
                            .then(res => {
                                const restaurantsNearMe = res.data.nearby_restaurants;

                                this.setState({
                                    restaurants: restaurantsNearMe
                                });

                                // Pick out a random retaurant from what the API returns
                                var randomRestaurant =
                                    restaurantsNearMe[
                                        Math.floor(Math.random() * restaurantsNearMe.length)
                                    ];

                                // Select only the data that you want
                                var finalResult = {
                                    name: randomRestaurant.restaurant.name,
                                    id: randomRestaurant.restaurant.id,
                                    rating: randomRestaurant.restaurant.user_rating.aggregate_rating,
                                    ratingColor: randomRestaurant.restaurant.user_rating.rating_color,
                                    address: randomRestaurant.restaurant.location.address,
                                    delivery: randomRestaurant.restaurant.is_delivering_now,
                                    typeOfFood: randomRestaurant.restaurant.cuisines
                                };

                                this.setState({
                                    restaurant: finalResult
                                });
                                console.info(this.state.restaurant);
                            })
                            .catch(err => console.info(err));
                    });
                    console.info(
                        `Latitude: ${this.state.latitude}. Longitude: ${this.state.longitude}`
                    );
                })
                .catch(err => console.info(err));

        });
        console.info(`IP : ${this.state.ip}`);
    })
    .catch(err => console.info(err));

Другие вопросы по теме