【问题标题】:React: Fetching data from a nested arrayReact:从嵌套数组中获取数据
【发布时间】:2018-10-15 10:57:49
【问题描述】:

5 月 4 日,我正在尝试使用 this REST API 做一个小小的星球大战 React 应用程序。我从people URL 获取数据,其中有几个嵌套数组链接到不同的 URL,这些 URL 也返回更多 JSON。

我需要做的是找到一种在映射人员 JSON 时从嵌套数组中获取数据的好方法。

所以我的应用程序 HTML 最终看起来像

// this would be something like `<p>{ data.name }</p>`
<p>Name: Luke Skywalker</p>
// data data more data

// the `FILMS` array comes from `data.films` which only holds URL's
<div>
  <p>Films</p>
</div>
<div>
  <p>The Empire Strikes Back</p>
  <p>Revenge of the Sith</p>
  // return the rest of movies character was in
</div>

目前,我的想法是将CharData 转换为一个类,并在fetch 内部调用多个componentDidMount,并让它设置状态,希望在this.state 对象上产生一个数组。但这需要为每一部单独的电影发生,我想要的只是标题。似乎有很多事情要返回一个值。

App.js

import React, { Component } from 'react';
import './App.css';

// components
import CharContainer from './comp/charcontainer/CharContainer';

class App extends Component {
  constructor() {
    super();
    this.state = {
      starwarsChars: []
    };
  }
  componentDidMount() {
    // feel free to research what this code is doing.
    // At a high level we are calling an API to fetch some starwars data from the open web.
    // We then take that data and resolve it our state.
    fetch('https://swapi.co/api/people')
      .then(res => {
        return res.json();
      })
      .then(data => {
        this.setState({ starwarsChars: data.results });
      })
      .catch(err => {
        throw new Error(err);
      });
  }
  render() {
    return (
      <div className="App">
        <h1 className="Header">React Wars</h1>

        {/* Char Container */
        (this.state.starwarsChars.length > 0)
          ?
            <CharContainer charData={ this.state.starwarsChars } />
          :
            <h2>Fetching Character Information...</h2>
        }
      </div>
    );
  }
}

export default App;

CharData.js

import React from 'react';

const CharData = props => {
  return (
    <React.Fragment>

      {
        props.charData.map((char, ind) => {
          return (
            <div className='char-card-container__char-card-wrapper'>
              <div key={ind + Date.now()} className="char-card-container__char-card">

                <h2 className='mt-2'>{char.name}</h2>
                <p className='mt-2'><span className='char-card__char-info-label'>Gender:</span> {char.gender}</p>
                <p className='mt-2'><span className='char-card__char-info-label'>Birth Year:</span> {char.birth_year}</p>
                <p className='mt-2'><span className='char-card__char-info-label'>Eye Color:</span> {char.eye_color}</p>
                <p className='mt-2'><span className='char-card__char-info-label'>Hair Color:</span> {char.hair_color}</p>
                <p className='mt-2'><span className='char-card__char-info-label'>Height:</span> {char.height}</p>
                <p className='mt-2'><span className='char-card__char-info-label'>Weight:</span> {char.mass}</p>
                <p className='mt-2'><span className='char-card__char-info-label'>Skin Color:</span> {char.skin_color}</p>

                <div className='mt-2'>
                  <div>
                    <p className='char-card__char-info-label'>Films</p>
                  </div>
                  <div>
                    {
                      char.films.map(film => {
                        return (
                          <p>{film}</p>
                        )
                      })
                    }
                  </div>
                </div>

                <div className='mt-2'>
                  <div>
                    <p className='char-card__char-info-label'>Specie</p>
                  </div>
                  <div>
                    {
                      char.species.map(specie => {
                        return (
                          <p>{specie}</p>
                        )
                      })
                    }
                  </div>
                </div>

                <div className='mt-2'>
                  <div>
                    <p className='char-card__char-info-label'>StarShips</p>
                  </div>
                  <div>
                    {
                      char.starships.map(starship => {
                        return (
                          <p>{starship}</p>
                        )
                      })
                    }
                  </div>
                </div>

                <div className='mt-2'>
                  <div>
                    <p className='char-card__char-info-label'>Vehicles</p>
                  </div>
                  <div>
                    {
                      char.vehicles.map(vehicle => {
                        return (
                          <p>{vehicle}</p>
                        )
                      })
                    }
                  </div>
                </div>

              </div>
            </div>
          );
        })
      }

    </React.Fragment>
  );
}

export default CharData;

【问题讨论】:

    标签: ajax reactjs fetch array.prototype.map


    【解决方案1】:

    您可以渲染&lt;FilmContainer film={film} /&gt;,而不是呈现&lt;p&gt;{film}&lt;/p&gt;,其中film 是一个URL,您可以采用与App 中类似的方式获取该URL。

    您最终可能会得到很多用于不同类型细节的容器。解决重复问题的一种方法是使用Render Props 方法。

    class FetchContainer extends Component {
      constructor() {
        super();
    
        this.state = {
          loading: true,
          data: null
        };
      }
    
      componentDidMount() {
        fetch(this.props.url)
          .then(res => {
            return res.json();
          })
          .then(data => {
            this.setState({
              loading: false, 
              data,
            });
          })
          .catch(err => {
            throw new Error(err);
          });
      }
    
      render() {
        return this.props.children({
          loading: this.state.loading,
          data: this.state.data
        });
      }
    }
    

    以下是如何使用此组件以个人详细信息显示电影信息:

    {char.films.map(film => (
      <FetchContainer url={film}>
        {({ loading, data }) => loading ? (
          <p>Loading film...</p>
        ) : (
          <p>{data.title}</p>
        )}
      </FetchContainer>
    ))}
    

    【讨论】:

    • 是的,这听起来绝对是一个不错的解决方案。我一直在努力意识到我的应用程序的时间复杂性,无论大小。我不是 100% 确定 React 如何渲染组件,但在我看来,这看起来像一个嵌套循环对吗? mapmap 中还是我错了?无论如何,这仍然是一个很好的答案,谢谢。
    • 你是对的,初始渲染将花费 O(a*b) 时间,但我不确定这个指标有多深入。当您想要显示具有未知数量元素的数据列表时,您无法避免嵌套循环。在实现标记逻辑之后,您应该关注的是 reducing the number of unnecessary re-renders 并使用 list virtualization 将渲染限制在当前视口。
    猜你喜欢
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多