【问题标题】:Issue using array of objects from API as JSON for d3 visualization使用来自 API 的对象数组作为 d3 可视化的 JSON 的问题
【发布时间】:2020-04-09 09:29:53
【问题描述】:

所以我构建了一个返回如下数组的 API:

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

我可以在我的 react 应用程序上使用它来显示表格,但现在我想将它用作 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;

问题是,当我使用 axios.get 传递从 API 获得的内容时,它会给出一个未定义的错误,就好像它无法解析数组中的对象一样。

另一方面,如果我手动插入相同的数组:

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
      })
     });

然后我只是简单地做: convert(this.state.aliens) 给我错误:Can add property children to 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、planet、parent})。如果您打算渲染一组子项,请改用数组。

_refreshAliens/

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

【问题讨论】:

  • 你能分享你的代码,你在哪里做 api 调用并将响应传递给你的转换函数。
  • @AadilMehraj 我刚刚编辑了我的帖子
  • 这一行写在哪里?转换(this.state.aliens)
  • 内部 render() {.....} as let data = convert(this.state.aliens

标签: javascript reactjs rest d3.js


【解决方案1】:

在 API 请求发生期间,aliens 状态将是一个空数组。您还需要在转换函数中处理这种情况。添加一个空检查以避免在这种情况下返回错误。

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>
    )

【讨论】:

  • 现在该函数不会引发错误,但它仍然会输出一些空值,这在我使用 D3 传递层次结构(转换(数据))时给我一个错误。是否可以忽略那些空子数组而不输出任何内容?谢谢!
  • 不应该是某个地方的else子句吗?我的网站现在卡在加载中。
  • 你不需要 else 你在第一个 if 子句中返回,确保你的条件是正确的。
  • 我编辑了我的帖子。我按照你说的做了,但是我的页面卡在加载中..
  • 更新了答案,确保你正确地从状态中解构外星人。
猜你喜欢
  • 2016-09-04
  • 1970-01-01
  • 1970-01-01
  • 2013-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多