Реакция - ожидаемое значение обещания Axios не определено - PullRequest
0 голосов
/ 02 октября 2018

Я пытаюсь создать приложение погоды, используя React, response-autosuggest для раскрывающегося списка доступных городов и для загрузки API Axios.

App.jsx

import React, { Component } from "react";
import CityWeather from './components/CityWeather';
import SearchWeather from './components/SearchWeather';




class App extends Component {

    constructor(props){
        super(props);
        this.state = {
            value: '',
            suggestedCities: [],
            cityWeatherData: [],
            currentWeather: [],
        }
    };

    handleCityWeatherData = (city) => {
        this.setState({
            cityWeatherData: city
        });
    };

    handleOnChange = (newValue) => {
        this.setState({
            value: newValue
        });
    }

    render() {

        // Finally, render it!
        return (
            <div>
                <SearchWeather suggestData={{value: this.state.value, suggestedCities: this.state.suggestedCities}} onSelectCity={this.handleCityWeatherData} onChange={this.handleOnChange}/>
                <CityWeather weatherData={this.state.cityWeatherData}/>
            </div>
        );
    }
}

export default App;

Apis.jsx

import Axios from "axios";

//local file
let cities = "./public/cities.json";


export default {
    getCities: function(){
        return  Axios.get(cities).then((res) => {
            console.log("from apis", res.data.cities);
            resolve(res.data.cities);
        }).catch((error) => {
            console.log("from apis.jsx", error);
            []
        });
    },
    getTest: function(){
        return 'hello';
    }
    //add api for weather
};

У меня проблемы с получением данных, поэтому в SearchWeather.jsx я хотел бы получитьсписок городов с помощью функции, const cities = apis.getCities(), где она извлекает данные из другого файла, Apis.jsx, где Axios используется по методу getCities.Ошибка возникает в api.getCities, в консоли написано <promise> pending, и я получаю неопределенное значение для переменной cities.Не знаю, как это сделать, я пытался добавить await до getCities в api.jsx, но ничего не сделал.Я могу использовать fetch вместо Axios, но я бы хотел использовать Axios и узнать больше о.Я уверен, что это нужно делать в const cities = apis.getCities(), но не знаю, как это сделать, я думаю, что мне нужно использовать решимость, но не знаю как.Новый, чтобы реагировать, так что я уверен, что что-то упустил.Мы будем благодарны за вашу помощь!

SearchWeather.jsx

import React, { Component } from "react";
import Axios from "axios";
import Autosuggest from 'react-autosuggest';
import apis from '../utils/apis';


const getSuggestions = (value) => {
    const inputValue = value.trim().toLowerCase();
    const inputLength = inputValue.length;


    const cities = apis.getCities().then((data) => {
        console.log(data);
        data;
    });

    console.log('calling from getSuggestions');
    console.log(cities); //this is undefined from const cities


    return inputLength === 0 ? [] : cities.filter(city =>

        city.name.toLowerCase().slice(0, inputLength) === inputValue
    );
};

// When suggestion is clicked, Autosuggest needs to populate the input
// based on the clicked suggestion. Teach Autosuggest how to calculate the
// input value for every given suggestion.
const getSuggestionValue = suggestion => suggestion.name;

// Use your imagination to render suggestions.
const renderSuggestion = suggestion => (
  <span>{suggestion.name}</span>
);

class SearchWeather extends Component {

    onChange = (event, { newValue }) => {
        this.props.onChange(newValue);
    };

    // Autosuggest will call this function every time you need to update suggestions.
    // You already implemented this logic above, so just use it.
    onSuggestionsFetchRequested = ({ value }) => {
        this.setState({
          suggestedCities: getSuggestions(value)
        });
    };

    // Autosuggest will call this function every time you need to clear suggestions.
    onSuggestionsClearRequested = () => {
        this.setState({
          suggestedCities: []
        });
    };

    renderSuggestionsContainer = ({ containerProps, children, query }) => {
        return (
            <div {...containerProps}>
                {children}
                <h5>I like showing up.</h5>
            </div>
        );
    };

    fetchCityWeather = (cityId) => {
        //fetching sample request
        Axios.get("/public/sampleWeather.json").then((response) => {
            if(response.status === 200){
                return response.data
            }
            else{
                console.log('fetchCityWeather - something went wrong');
            }

        })
        .catch((error) => {
            console.log(error);
        });
    };

    onSuggestionSelected = (event, { suggestion, suggestionValue, suggestionIndex, sectionIndex, method }) => {
        console.log(suggestion);
        console.log(method);

        if(method == 'click'){
            let cityId = suggestion.id;
            let data = this.fetchCityWeather(cityId);
            this.props.onSelectCity(data); //pass data to parent
        }
    };


    componentDidMount = () => {
        console.log('componentDidMount');
    }


    render(){
        const value = this.props.suggestData.value;
        const suggestedCities = this.props.suggestData.suggestedCities;

        // Autosuggest InputProps
        const inputProps = {
          placeholder: 'Type your city',
          value,
          onChange: this.onChange
        };

        return(
            <Autosuggest
                suggestions={suggestedCities}
                onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
                onSuggestionsClearRequested={this.onSuggestionsClearRequested}
                getSuggestionValue={getSuggestionValue}
                renderSuggestion={renderSuggestion}
                inputProps={inputProps} 
                shouldRenderSuggestions = {(v) => v.trim().length > 0}
                renderSuggestionsContainer={this.renderSuggestionsContainer}
                onSuggestionSelected={this.onSuggestionSelected}
            />
        );
    }
}

export default SearchWeather;

Примечание. Я помещаю вызовы API в другой файл только для организационных целей и хотел бы сохранить его таким, если это не так.правильный способ сделать это.

Дополнительная информация:

Я изменил const cities на это:

const cities = apis.getCities().then((data) => {
        console.log("from getCities", data);
        return data;
    });

и заметил в консоли следующее по порядку:

от console.log(cities) в SearchWeather

Promise {<pending>}

от Apis.jsx console.log("from apis", res.data.cities);, данные

from apis (4) [{..},{..}]

из SearchWeather, console.log("from getCities", data);

from getCities (4) [{..},{..}]

Не знаю, помогает ли это, но const cities пропускается, затем возвращается и печатает фактические данные

Ответы [ 2 ]

0 голосов
/ 02 октября 2018

Первое, что я заметил, это:

let cities = "./public/cities.json";

Чтобы прочитать файл в свой код, вы должны использовать require, например:

let cities = require('./public/cities.json');

или как в ES6

import cities from './public/cities.json'

все, что вам хорошо.

Второе, что я заметил, это то, что вы возвращаетесьАксиос после выполнения первого обещания (в котором вы ничего не возвращаете).Вы могли бы пойти так:

getCities: function(){
   return  Axios.get(cities)
},

или вот так:

    getCities: function(){
        return  Axios.get(cities).then(res => res.data.cities).catch(...) // return cities
    },

Почему это так?

Потому что после обертывания с помощью функции .then,вы решаете это, и все, что будет возвращено в этом, становится еще одним обещанием, позволяющим вам связать его с другим тогда, или, в вашем случае, с этим:

apis.getCities().then((data) => {
    const cities = data
});

Если вы используете первое, которое я написалВы получите ответ обратно в аргументе данных в этой функции.Второй даст вам города прямо в данные.

Редактировать:

Поскольку я неправильно прочитал код, и мой ответ не имел никакого смысла, я редактирую свой ответ:

Чтобы получить ответ от асинхронного обещания, вы должны передать функцию обратного вызова (или выполнить асинхронное / ожидание) вашей функции, например:

Apis.jsx

/**/
    getCities : cb => Axios.get(cities).then(res => cb(res.data.cities))
/**/

SearchWeather.jsx

const getSuggestions = (value, cb) => {
/**/
    apis.getCities().then(cities => {
       /* your logic to filter cities goes here */

       // return your filtered cities here 
       return cb(filteredCities)
    });
}

class SearchWeather extends Component{
/**/
    onSuggestionsFetchRequested = ({ value }) => {
        const cb = suggestedCities => this.setState({ suggestedCities })

        return getSuggestions(value, cb)
    };
/**/
}

cb (или обратный вызов) будет запущен после выполнения обещания.

0 голосов
/ 02 октября 2018

Axios не может запросить URL-адрес, например let cities = "./public/cities.json";

Если вы поместите этот json-файл в общую папку, вы можете установить URL-адрес, например

http://localhost:3001/public/cities.json

незабыл порт.Это HTTP-запрос к хосту, а не просто чтение локального файла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...