【问题标题】:reactjs render array of objects into a list gives an errorreactjs将对象数组渲染到列表中会出错
【发布时间】:2016-10-24 00:38:10
【问题描述】:

所以我从获取的 json 文件创建一个对象,并在 showResult() 函数中根据某些条件将一个对象添加到数组 finalArray,然后我将此数组传递给组件 Card,这应该呈现一个列表,但它给我一个错误 items.map 不是一个函数,但如果我改变 finalArray:this.state.finalArray.push(新用户(价格、位置、图像、名称、分数)) 到 finalArray: this.state.finalArray.concat(new user(price, location, image, name, score))

然后它可以工作,但它只显示最后一个对象,仅显示 1 个列表项,这不是我想要的,有人可以帮助指出错误或如何正确执行此操作,因为我是新的反应和 javascript

import React from 'react';
import Card from './Card.js';

export default class Slider extends React.Component {

 constructor() {
    super()
    this.state = {
        imgArray: [ "/img/work1.jpg", "/img/work2.jpg", "/img/work3.jpg"],
        imgNo: 0,
      url: "https://www.deskbookers.com/nl-nl/sajax.json?q=Amsterdam&type=-&people=any&favorite=0&pid=&sw=52.293753%2C4.634942&ne=52.455562%2C5.162286&ids=17201%2C19640%2C13692%2C13691%2C12136%2C17938%2C15292%2C14886%2C14885%2C14884%2C14883%2C15730%2C15353%2C15351%2C15330%2C15080%2C17290%2C15454%2C15451%2C15379",
        current: "/img/work1.jpg",
      search: '',
      resultObject: null,
      finalArray: [],
      headlines: ["Pink Floyd Office", "Led Zeppelin Mania", "Central Perk Friends"],
      headline : "Pink Floyd Office"
    };
  }

  componentDidMount(){
  this.serverRequest = $.get(this.state.url, function(result){
    var info =  result;
    console.log(info);
    this.setState({
      resultObject:info
    })
  }.bind(this));
 }

  nextImg(){
    if(this.state.imgNo < 2 && this.state.imgNo >=0 ){
        this.setState({
        imgNo : ++this.state.imgNo ,
        current: this.state.imgArray[this.state.imgNo],
      headline: this.state.headlines[this.state.imgNo]
      })
      }
 }

  prevImg(){
    if(this.state.imgNo >= 1  && this.state.imgNo < 3 ){
        this.setState({
        imgNo : --this.state.imgNo,
        current: this.state.imgArray[this.state.imgNo],
      headline: this.state.headlines[this.state.imgNo]
      })
      }
  }

  searchQuery(e){
    this.setState({
      search: e.target.value
    })
  }

  showResult(){

    for(var i=0 ; i<this.state.resultObject.rows.length; i++){
      if(this.state.search.toLowerCase() == this.state.resultObject.rows[i].location_city.toLowerCase()){
        var price = this.state.resultObject.rows[i].day_price;
        var location=(this.state.resultObject.rows[i].address[0]+", "+this.state.resultObject.rows[i].address[1]+", "+this.state.resultObject.rows[i].address[2]);
        var image=this.state.resultObject.rows[i].image_urls2[0];
        var name=this.state.resultObject.rows[i].location_name;
        var score=this.state.resultObject.rows[i].location_rating;
        if( price!=null && location!=null && image!=null && name!=null && score !=null){
          function user(price, location, image, name, score){
          this.price = price;
          this.location = location;
          this.image = image;
          this.name = name;
          this.score = score;
        }
          this.setState({
            finalArray: this.state.finalArray.push(new user(price, location, image, name, score))
          })
      }
        $(".card-list").show();
        $('html,body').animate({
            scrollTop: $(".card-list").offset().top},
            'slow');
      }
        else{
          $(".alert-box, .cancel").animate( { "opacity": "show", bottom:"0"} , 1250 );
          $(".alert-box, .cancel").animate( { "opacity": "hide", bottom:"0"} , 3750 );
          this.setState({
            search: ""
          })
          $(".card-list").hide();
          break;
        }
    }

  }

 render(){

    return(
      <div>
        <div class="slider ">
            <div class="img-container">
                <img src={this.state.current} class="main-img" />
                <div class="headline"><span>{this.state.headline}</span></div>
            </div>
            <img src="/img/slider-left.png" class="slider-arrow" onClick={this.prevImg.bind(this)} />
            <img src="/img/slider-right.png" class="slider-arrow slider-right" onClick={this.nextImg.bind(this)} />
          <div class="search-container">
            <img src="/img/cancel.png" class="cancel hide"/>
            <span class="alert-box hide">No offices available in this city, please try another one!</span>
            <input onChange={this.searchQuery.bind(this)} value={this.state.search} type="text" name="search"  placeholder="City name..." class="search-bar" />
            <button disabled={!this.state.search} onClick={this.showResult.bind(this)} class="search-button">Sit me!</button>
          </div>
        </div>
        <Card finalArray={this.state.finalArray}></Card>
      </div>    
      );
  }
}


import React from 'react';

export default class Card extends React.Component {


 render(){
    var items = this.props.finalArray;
    var itemslist = items.map(function(item,index){
          return(
              <li key={index} class="card">
                <img src={item.image} class="card-img" />
                <div>
                  <div class="card-info">
                    <p class="workplace-name">{item.name}</p>
                    <span class="score">{item.score}</span>
                    <p class="location">{item.location}</p>
                  </div>
                  <div class="card-footer">
                    <p class="price">{item.price} &euro;</p>
                  </div>
                </div>
              </li>
          );})
    return(
      <ul class="card-list">
        { itemslist }
       </ul> 

      );

  }
}

【问题讨论】:

    标签: javascript arrays object reactjs frontend


    【解决方案1】:

    The .push method returns the new length of the array。所以当你这样做时

    this.setState({
        finalArray: this.state.finalArray.push(...)
    });
    

    您正在将this.state.finalArray 的值从一个数组 更改为一个数字。当然数字没有.map 方法。

    如果要在数组中添加新元素并创建新数组,可以使用.concat 代替:

    this.setState({
        finalArray: this.state.finalArray.concat(...)
    });
    

    总体而言,您的代码似乎比它必须的要复杂。例如。 user 函数是不必要的,直接创建对象即可。 null 检查也可能是不必要的。

    我不太确定您希望您的代码如何工作,但在我看来,showResult 结果方法应该是这样的:

    showResults() {
      var search = this.state.search.toLowerCase();
      var finalArray = this.state.resultObject.rows
        .filter(row => search == row.location_city.toLowerCase())
        .map(row => ({
          price: row.day_price,
          location: rows.address.slice(0,3).join(', '),
          image: row.image_urls2[0],
          name:  row.location_name,
          score: row.location_rating,
        }))
        .filter(user => user.price != null &&
          user.image != null &&
          user.name != null &&
          user.score != null
        );
    
      this.setState(
        {
          finalArray,
          search: finalArray.length > 0 ? this.state.search : '',
        },
        () => {
          // This is executed after the component updated
          if (finalArray.length > 0) {
            $(".card-list").show();
            $('html,body').animate({
              scrollTop: $(".card-list").offset().top
            }, 'slow');
          } else {
            $(".alert-box, .cancel").animate( { "opacity": "show", bottom:"0"} , 1250 );
            $(".alert-box, .cancel").animate( { "opacity": "hide", bottom:"0"} , 3750 );
            $(".card-list").hide();
          }
        }
      );
    } 
    

    也就是说,首先创建数据、对象数组并更新组件状态。更新后,检查是否有结果根据该结果显示或隐藏列表。请注意,手动更改组件的样式并不是您通常使用 React 所做的事情。

    【讨论】:

    • 但是当我使用 concat 时只返回最后一个数组,导致只显示一个列表项,其余的被忽略,我该如何解决这个问题?
    • 啊,我没有注意到您的代码在循环中。让我更新我的答案。
    • 更新了我的答案。
    • 我已经用你的替换了我的 showResult 函数,但是现在当我点击按钮时,它实际上什么也没做,甚至在控制台@Felix Kling 中也没有给出错误或任何东西
    • 哦,对不起,那是我的错,它工作得很好,非常感谢
    猜你喜欢
    • 2017-11-06
    • 2021-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-13
    • 2017-10-23
    • 2020-09-06
    相关资源
    最近更新 更多