Реакция: выборка данных из вложенного массива - PullRequest
0 голосов
/ 05 мая 2018

В течение 4 мая я пытаюсь создать небольшое приложение React для Star Wars с этим REST API. Я извлекаю данные из URL-адреса people , и внутри него есть несколько вложенных массивов, которые ссылаются на различные 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;

1 Ответ

0 голосов
/ 05 мая 2018

Вместо рендеринга <p>{film}</p> вы можете отрендерить <FilmContainer film={film} />, где film - это URL, который вы можете получить аналогично тому, как вы делаете в App.

Возможно, у вас будет много таких контейнеров для разного рода деталей. Одним из способов устранения дублирования было бы использование подхода 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>
))}
...