Проблема с использованием массива объектов из API как JSON для визуализации d3 - PullRequest
0 голосов
/ 09 апреля 2020

Поэтому я создал API, который возвращает массив, подобный следующему:

[{"id":1,"name":"Josh","parent":null},
{"id":2,"name":"Peter","parent":1},{"id":3,"name":"Mary","parent":2}]

Я могу использовать его в своем приложении реакции для отображения таблицы, но теперь я хотел бы использовать его в качестве ввода для графа d3. Поэтому я построил функцию, которая принимает массив объектов и преобразует его в один большой иерархический объект.

function convert(array){    
    var map = {};
    for(var i = 0; i < array.length; i++){
        var obj = array[i];
        obj.children= [];

        map[obj.id] = obj;

        var parent = obj.parent || '-';
        if(!map[parent]){
            map[parent] = {
                children: []
            };
        }
        map[parent].children.push(obj);
    }

    return map['-'].children;

Проблема заключается в том, что когда я передаю то, что получаю из API, используя ax ios. получить, он дает неопределенную ошибку, как если бы он не был в состоянии проанализировать объекты внутри массива.

Если, с другой стороны, я вручную вставлю тот же массив:

const rawData2 = [{"id":1,"name":"Javier","parent":null},
{"id":2,"name":"Nerea","parent":1}, 
{"id":3,"name":"Yolo","parent":2}]

это работает без проблем.

Я не знаю, что еще попробовать. Я попробовал stringfy, разобрать json, используя карту, подобную этой:

var result = this.state.persons.map(person => ({id: person.id, name: person.name, parent: 
person.parent}))

Ничего не работает.

Любая помощь?

РЕДАКТИРОВАТЬ: я думаю, что проблема имеет что-то что связано с тем фактом, что JS является асинхронным, поэтому, когда я передаю ответ API своей функции преобразования, я также пропускаю несколько пустых массивов, прежде чем фактически передать фактические массивы из данных.

Как я могу заблокировать данных, чтобы избежать этого? Извините за недостаток технического словаря, но я совершенно не знаком с языками этого типа.

Edit2: так я получаю данные из API:

componentWillMount() {
    this._refreshAliens()
  }

  _refreshAliens () {
    axios.get('http://localhost:8080/aliens').then((response) => {
      this.setState({
        aliens: response.data
      })
     });

А потом я просто do: convert (this.state.aliens), выдающая мне ошибку: может добавить дочерние свойства в undefined.

Если я console.log (this.state.aliens):

я получу несколько [], [], а затем (3) [{…}, {…}, {…}] с правильными данными.

РЕДАКТИРОВАТЬ:

render() {
    let aliens = this.state.aliens.map((alien) => {
      return (
        <tr key={alien.id}>
          <td>{alien.id}</td>
          <td>{alien.name}</td>
          <td>{alien.type}</td>
          <td>{alien.planet}</td>
          <td>{alien.parent}</td>
          <td>
            <Button color="success" size="sm" className="mr-2" onClick={this.editAlien.bind(this, alien.id, alien.name, alien.planet)}>Edit</Button>
            <Button color="danger" size="sm" onClick={this.deleteAlien.bind(this, alien.id)}>Delete</Button>
          </td>
        </tr>
      )
      })
    const { all = [] } = this.state.aliens
      if (Array.isArray(all) && all.length === 0) {
        return <p>Loading...</p>
      } 
    return (

      <div className="App container">

          ...........

Ошибка редактирования:

Ошибка: объекты недопустимы как дочерний элемент React (найдено: объект с ключами {id, name, type, pl anet, parent}). Если вы хотите отобразить коллекцию дочерних элементов, используйте вместо этого массив.

_refreshAliens /

  57 | }
  58 | _refreshAliens () {
  59 |   axios.get('http://localhost:8080/aliens').then((response) => {
> 60 |     this.setState({
     | ^  61 |       aliens: response.data
  62 |     })
  63 | 

1 Ответ

1 голос
/ 09 апреля 2020

Во время выполнения запроса API состояние пришельцев будет пустым массивом. Вы должны обрабатывать этот случай также и в вашей функции преобразования. В этом случае добавьте пустую проверку, чтобы избежать ошибки при возврате.

function convert(array = []){    
    var map = {};
    for(var i = 0; i < array.length; i++){
        var obj = array[i];
        obj.children= [];

        map[obj.id] = obj;

        var parent = obj.parent || '-';
        if(!map[parent]){
            map[parent] = {
                children: []
            };
        }
        map[parent].children.push(obj);
    }

    return map['-'] ? map['-'].children : null;
}

Редактировать: также добавьте загрузчик, чтобы избежать дальнейшей ошибки в случае, если доступны данные из API, например, в функции рендеринга:

render() {
  const { aliens = [] } = this.state
  if (Array.isArray(aliens) && aliens.length === 0) {
    return <p>Loading...</p>
  }

  return (
    // Do your stuff...
  )

}

РЕДАКТИРОВАТЬ 2: Убедитесь, что вы должным образом уничтожить иностранцев из государства. Вот как должен выглядеть полученный код:

render() {
  const {aliens = []}= this.state;

  if (!Array.isArray(aliens) || aliens.length === 0) {
    return <p>Loading...</p>
  } 

  return (

      <div className="App container">
         {
            aliens.map((alien) => {
              return (
                <tr key={alien.id}>
                  <td>{alien.id}</td>
                  <td>{alien.name}</td>
                  <td>{alien.type}</td>
                  <td>{alien.planet}</td>
                  <td>{alien.parent}</td>
                  <td>
                    <Button color="success" size="sm" className="mr-2" onClick={this.editAlien.bind(this, alien.id, alien.name, alien.planet)}>Edit</Button>
                    <Button color="danger" size="sm" onClick={this.deleteAlien.bind(this, alien.id)}>Delete</Button>
                  </td>
                </tr>
              )
            })
         }

         // Other stuff...
      </div>
    )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...