react.js中的promise,model属性是promise而不是array

时间:2018-03-30 20:08:07

标签: javascript reactjs

我正在尝试实施一个餐厅应用,用户可以在菜单上添加菜肴。菜单将显示在侧栏中。菜肴信息通过API提供。我遇到了API请求/承诺的问题。我在DinnerModel中存储了一系列菜肴。我正在DinnerModel向API发出请求。

当我通过点击IngredientsList中的添加按钮向菜单添加菜肴时,我会被重定向到显示Sidebar的屏幕。但在Sidebar中,菜肴是NaN。 console.logs显示this.state.menu中的Sidebar实际上是承诺,而不是数组。我很难理解为什么会这样做以及如何处理它。

请注意,Sidebar中的更新应该运行modelInstance.getFullMenu(),它返回一个数组。但相反,承诺会被退回。为什么?我该怎么做才能解决这个问题?

这是我的代码:

Dinnermodel.js:

const DinnerModel = function () {

  let numberOfGuests = 4;
  let observers = [];
  let selectedDishes = [];


  // API Calls

  this.getAllDishes = function (query, type) {
    const url = 'https://spoonacular-recipe-food-nutrition-v1.p.mashape.com/recipes/search?query='+query+"&type="+type;
    return fetch(url, httpOptions)
      .then(processResponse)
      .catch(handleError)


   }
  //function that returns a dish of specific ID
    this.getDish = function (id) {
    let url = "https://spoonacular-recipe-food-nutrition-v1.p.mashape.com/recipes/"+id+"/information";
    return fetch(url, httpOptions)
      .then(processResponse)
      .catch(handleError)
  }



  // API Helper methods

  const processResponse = function (response) {
    if (response.ok) {
      return response.json();
    }
    throw response;
  }


    this.addToMenu = function(id, type){
    var newDish = this.getDish(id).then()
    newDish.dishType = type;
    selectedDishes.push(newDish);
    notifyObservers();

  }

    //Returns all the dishes on the menu.
    this.getFullMenu = function() {
        return selectedDishes;
    }

DishDetails.js:

class DishDetails extends Component {
    constructor(props) {
        super(props);

        this.state = {
            id: props.match.params.id,
            status: "INITIAL",
            type: props.match.params.type,
        };
    }

    addToMenu (){
        modelInstance.addToMenu(this.state.id, this.state.type);
        this.props.history.push("/search/"+this.state.query+"/"+this.state.type);
    }

    componentDidMount = () => {
        modelInstance.getDish(this.state.id)
        .then(dish=> {
            this.setState({
                status:"LOADED",
                ingredients: dish.extendedIngredients,
                dishText: dish.winePairing.pairingText,
                pricePerServing: dish.pricePerServing,
                title: dish.title,
                img: dish.image,
                instructions: dish.instructions,
            })
        })
        .catch(()=>{
            this.setState({
                status:"ERROR",
            })
        })
    }

    render() {
        switch(this.state.status){
            case "INITIAL":
                return (
                    <p>Loading...</p>
                );
            case "ERROR":
                return (
                    <p>An error has occurred, please refresh the page</p>
                );
        }
        return (
                <IngredientsList ingredients={this.state.ingredients} pricePerServing={this.state.pricePerServing} id={this.state.id} onButtonClick={() => this.addToMenu()}/>
                <Sidebar />
        );
    }
}
export default withRouter(DishDetails);

Sidebar.js:

class Sidebar extends Component {

  constructor(props) {
    super(props)
    // we put on state the properties we want to use and modify in the component
    this.state = {
      numberOfGuests: modelInstance.getNumberOfGuests(),
      menu: modelInstance.getFullMenu(),
    }
    modelInstance.addObserver(this);
  }

  // this methods is called by React lifecycle when the 
  // component is actually shown to the user (mounted to DOM)
  // that's a good place to setup model observer
  componentDidMount() {
    modelInstance.addObserver(this)
  }

  // this is called when component is removed from the DOM
  // good place to remove observer
  componentWillUnmount() {
    modelInstance.removeObserver(this)
  }

  handleChangeGuests(event){
    let noOfGuests = event.target.value;
    modelInstance.setNumberOfGuests(noOfGuests);
  }

  // in our update function we modify the state which will
  // cause the component to re-render
  update() {
    this.setState({
      numberOfGuests: modelInstance.getNumberOfGuests(),
      menu: modelInstance.getFullMenu(),
    })
    console.log("menu in Sidebar.js");
    console.log(this.state.menu);
  }

  render() {
    //console.log(this.state.menu);
    let menu = this.state.menu.map((dish)=>
      <div key={"menuitem-"+dish.id} className="menuitemwrapper">
        <div className="menuitem">
          <span className="dishname">{dish.title}</span>
          <span className="dishprice">{dish.pricePerServing*modelInstance.getNumberOfGuests()}</span>
        </div>
      </div> 
    );
    return (
              <div id="sidebar-dishes">   
                {menu}
              </div>  
    );
  }
}

export default Sidebar;

IngredientsList.js:

class IngredientsList extends Component{
    constructor(props){
        super(props);
        this.state = {
            ingredients: props.ingredients,
            pricePerServing: props.pricePerServing,
            id: props.id,
            noOfGuests: modelInstance.getNumberOfGuests(),
        }
        modelInstance.addObserver(this);
    }
    update(){
        if(this._ismounted==true){
            this.setState({
                noOfGuests: modelInstance.getNumberOfGuests(),
            });
        }
    }
    componentDidMount(){
        this._ismounted = true;
    }
    componentWillUnmount(){
        this._ismounted = false;
    }
    render () {
        return (
            <button onClick={() => this.props.onButtonClick()} type="button" className="btn btn-default">Add to menu</button>
        );
    }
}   
export default IngredientsList;

编辑:

DinneModel.addToMenu更改为:

    this.addToMenu = function(id, type){
    var newDish = this.getDish(id)
    .then(()=>{
      newDish.dishType = type;
      selectedDishes.push(newDish);
      notifyObservers();
    });
  }

我仍然可以通过Sidebar.js中的console.logNaN Sidebar中的render在控制台中记录一个承诺。

1 个答案:

答案 0 :(得分:0)

getDish不在您的代码中,但我认为它会返回一个承诺。 this.getDish(id).then()也会返回一个承诺。这就是selectedDishes数组在其中承诺的原因。

this.addToMenu = function(id, type){
    var newDish = this.getDish(id).then()
    newDish.dishType = type;
    selectedDishes.push(newDish);
    notifyObservers();
}

要获取实际的newDish数据,您需要为then使用回调函数。

this.addToMenu = function(id, type){
    this.getDish(id).then(function (newDish) {
        newDish.dishType = type;
        selectedDishes.push(newDish);
        notifyObservers();
    });
}