【问题标题】:React - Axios promise pending value undefinedReact - Axios 承诺待定值未定义
【发布时间】:2018-10-02 14:34:12
【问题描述】:

我正在尝试使用 React 构建一个天气应用程序,react-autosuggest 用于列出可用城市的下拉列表以及用于获取 Axios 的 api。

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,在控制台中显示&lt;promise&gt; pending,我得到cities 变量的未定义。不知道该怎么做,我尝试在api.jsx 中的getCities 之前添加await,但没有做任何事情。我可以使用fetch 而不是Axios,但我想使用Axios 并了解更多信息。我确定它必须在const cities = apis.getCities() 中完成,但不知道该怎么做,我想我需要使用 resolve 但不知道怎么做。新的反应,所以我确定我错过了一些东西。您的帮助将不胜感激!

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) in SearchWeather

Promise {&lt;pending&gt;}

来自Apis.jsxconsole.log("from apis", res.data.cities);,数据

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

来自SearchWeatherconsole.log("from getCities", data);

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

不知道这是否有帮助,但 const cities 被跳过然后返回并打印实际数据

【问题讨论】:

    标签: javascript reactjs webpack axios autosuggest


    【解决方案1】:

    Axios 无法请求像 let cities = "./public/cities.json"; 这样的 URL

    如果你把这个 json 文件放在公用文件夹中,你可以设置 URL 像

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

    别忘了端口。这是对主机的 HTTP 请求,而不仅仅是读取本地文件。

    【讨论】:

    • 听起来更像?
    • @SungKim 我从 React.js 开始时也有类似的错误,所以我认为这种方式可以解决
    • Axios 能够读取它,因为该文件位于构建文件夹中
    【解决方案2】:

    我注意到的第一件事是:

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

    为了将文件读入你的代码,你必须使用require,像这样:

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

    或者在 ES6 中

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

    只要你休息得好。

    我注意到的第二件事是,在第一个承诺解决后,您将返回 Axios(其中您根本没有返回任何东西)。你可以这样:

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

    或者这个:

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

    这是为什么?

    因为在用 .then 函数包装它之后,你正在解决它,然后它在 this 中返回的任何内容都成为另一个承诺,允许你将它与另一个然后链接,或者在你的情况下,这个:

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

    如果使用我写的第一个,你会在这个函数的 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(或回调)将在解决 promise 后触发。

    【讨论】:

    • axios 可以在没有require 的情况下读取文件,该文件存在于构建文件夹中。我尝试了第一种方法,但仍然得到了未决的承诺。那么const cities 应该是什么? const cities = apis.getCities();?如果做第二种方式,函数中的cb是什么?
    • 我正在修正我的答案,因为我误读了你的代码。实际上,最初的 cb 应该是一个回调,因为为了检索 promise 的结果(不进行异步/等待),它带有一个回调。
    猜你喜欢
    • 1970-01-01
    • 2016-03-21
    • 2018-09-10
    • 1970-01-01
    • 2021-07-07
    • 2016-12-10
    • 1970-01-01
    • 2022-01-22
    • 2022-01-27
    相关资源
    最近更新 更多