Reactjs:迭代嵌套的json数组

时间:2016-07-22 14:27:23

标签: json reactjs

我有一个类似树状结构的json文件,它可以在几个级别上,看起来像这样,我试图将其转换为菜单(子元素为子菜单):

[
  {
    "label": {
      "en": "Home"
    },
    "icon": "/images/nav/home.png",
    "link": "/",
    "type": "basic"
  },
  {
    "label": {
      "en": "Channels"
    },
    "icon": "/images/nav/channels.png",
    "type": "children",
    "children": [
      {
        "label": {
          "en": "Getting Started"
        },
        "link": "/getting-started",
        "type": "basic"
      },
      {
        "label": {
          "en": "Recommendations"
        },
        "link": "/recommendations",
        "type": "basic"
      },
      {
        "label": {
          "en": "Calendar View"
        },
        "link": "/calendar",
        "type": "basic"
      },
      {
        "label": {
          "en": "My Pictures"
        },
        "link": "/account/media",
        "type": "basic"
      },
      {
        "type": "space"
      },
      {
        "label": {
          "en": "All Channels"
        },
        "link": "/channels",
        "type": "basic"
      },
      {
        "label": {
          "en": "Channel 1"
        },
        "link": "/channels/channel-1",
        "type": "statuses",
        "datasource": "/data/1",
        "children": [
          {
            "label": {
              "en": "Channel 1-1"
            },
            "link": "/channels/channel-1-1",
            "type": "basic"
          },
          {
            "label": {
              "en": "Channel 1-2"
            },
            "link": "/channels/channel-1-2",
            "type": "basic"
          },
          {
            "label": {
              "en": "Channel 1-3"
            },
            "link": "/channels/channel-1-3",
            "type": "basic"
          },
          {
            "label": {
              "en": "Channel 1-4"
            },
            "link": "/channels/channel-1-4",
            "type": "basic"
          },
          {
            "label": {
              "en": "Channel 1-5"
            },
            "link": "/channels/channel-1-5",
            "type": "basic"
          }
        ]
      },
      {
        "label": {
          "en": "Channel 2"
        },
        "link": "/channels/2",
        "type": "statuses",
        "datasource": "/data/2",
        "children": [
          {
            "label": {
              "en": "Channel 2"
            },
            "link": "/channels/channel-2",
            "type": "basic"
          },
          {
            "label": {
              "en": "Channel 2-1"
            },
            "link": "/channels/channel-2-1",
            "type": "basic"
          },
          {
            "label": {
              "en": "Channel 2-2"
            },
            "link": "/channels/channel-2-2",
            "type": "basic"
          },
          {
            "label": {
              "en": "Channel 2-3"
            },
            "link": "/channels/channel-2-3",
            "type": "basic"
          },
          {
            "label": {
              "en": "Channel 2-4"
            },
            "link": "/channels/channel-2-4",
            "type": "basic"
          }
        ]
      },
      {
        "type": "custom",
        "content": "<div><span class=\"green_bull\">&bull;</span>Currently Online</div><div><span class=\"red_bull\">&bull;</span>Currently Offline</div>"
      }
    ]
  },
  {
    "label": {
      "en": "Shows"
    },
    "icon": "/images/nav/shows.png",
    "type": "children",
    "children": [
      {
        "label": {
          "en": "LIVE"
        },
        "link": "/live",
        "type": "basic"
      },
      {
        "label": {
          "en": "Browse Shows"
        },
        "link": "/live",
        "type": "basic"
      },
      {
        "label": {
          "en": "Full Schedule"
        },
        "link": "/live",
        "type": "basic"
      },
      {
        "label": {
          "en": "Upcoming Shows"
        },
        "type": "components",
        "component": "navShow",
        "datasource": "/shows/upcoming?limit=3"
      }
    ]
  },
  {
    "label": {
      "en": "Community"
    },
    "icon": "/images/nav/community.png",
    "type": "children",
    "children": [
      {
        "label": {
          "en": "Latest"
        },
        "link": "/community",
        "type": "basic"
      },
      {
        "label": {
          "en": "Best of"
        },
        "link": "/community/highlight",
        "type": "basic"
      },
      {
        "label": {
          "en": "Discussion Boards"
        },
        "link": "http://forum.slooh.askmp.ca/",
        "type": "basic"
      },
      {
        "label": {
          "en": "Rankings"
        },
        "link": "/community/rankings",
        "type": "basic"
      },
      {
        "label": {
          "en": "Full Listings"
        },
        "link": "/community/listings",
        "type": "basic"
      },
      {
        "type": "space"
      },
      {
        "label": {
          "en": "Hot this Month"
        },
        "type": "basic-loaded",
        "datasource": "/community/hot"
      },
      {
        "type": "space"
      },
      {
        "type": "component",
        "component": "nav",
        "datasource": "/data/nav"
      },
      {
        "type": "custom",
        "content": "[social media HTML]"
      }
    ]
  },
  {
    "label": {
      "en": "About"
    },
    "icon": "/images/nav/about.png",
    "type": "children",
    "children": [
      {
        "label": {
          "en": "Our Values"
        },
        "link": "/about",
        "type": "basic"
      },
      {
        "label": {
          "en": "In the News"
        },
        "link": "/about/media",
        "type": "basic"
      },
      {
        "label": {
          "en": "The Team"
        },
        "link": "/about/#team",
        "type": "basic"
      },
      {
        "label": {
          "en": "Guests"
        },
        "link": "/about/#guests",
        "type": "basic"
      },
      {
        "label": {
          "en": "Partners"
        },
        "link": "/about/#partners",
        "type": "basic"
      },
      {
        "label": {
          "en": "Media Kit"
        },
        "link": "/about/media",
        "type": "basic"
      },
      {
        "label": {
          "en": "Contact Us"
        },
        "link": "/about/#contact",
        "type": "basic"
      },
      {
        "label": {
          "en": "Upcoming Shows"
        },
        "type": "components",
        "component": "navShow",
        "datasource": "/data/shows/upcoming?limit=1"
      }
    ]
  },
  {
    "label": {
      "en": "Help"
    },
    "icon": "/images/nav/help.png",
    "link": "/",
    "type": "children",
    "children": [
      {
        "label": {
          "en": "New here?"
        },
        "link": "/about",
        "type": "basic"
      },
      {
        "type": "space"
      },
      {
        "label": {
          "en": "Guides"
        },
        "link": "/help",
        "type": "basic"
      },
      {
        "label": {
          "en": "Troubleshooting"
        },
        "link": "/help/#troubleshooting",
        "type": "basic"
      },
      {
        "label": {
          "en": "Practice Activities"
        },
        "link": "/help#practice",
        "type": "basic"
      },
      {
        "label": {
          "en": "Image Management"
        },
        "link": "/help/images",
        "type": "basic"
      },
      {
        "label": {
          "en": "Photography 101"
        },
        "link": "/help/photography",
        "type": "basic"
      },
      {
        "label": {
          "en": "What’s What?"
        },
        "link": "/community/whats",
        "type": "basic"
      },
      {
        "label": {
          "en": "Hints and Tips"
        },
        "link": "/help/#hints",
        "type": "basic"
      },
      {
        "type": "space"
      },
      {
        "label": {
          "en": "Trouble Logging In?"
        },
        "link": "/help/account",
        "type": "basic"
      },
      {
        "label": {
          "en": "Pricing Tiers"
        },
        "link": "/help/#account",
        "type": "basic"
      },
      {
        "label": {
          "en": "Account FAQs"
        },
        "link": "/help/#account",
        "type": "basic"
      },
      {
        "label": {
          "en": "Shows FAQs"
        },
        "link": "/help/shows",
        "type": "basic"
      },
      {
        "label": {
          "en": "Reservations FAQs"
        },
        "link": "/help/faqs",
        "type": "basic"
      },
      {
        "type": "space"
      },
      {
        "label": {
          "en": "Contact Customer Support"
        },
        "link": "/help/contact",
        "type": "basic"
      },
      {
        "label": {
          "en": "Site Feedback"
        },
        "link": "/help/contact#feedback",
        "type": "basic"
      }
    ]
  },
  {
    "label": {
      "en": "Settings"
    },
    "icon": "/images/nav/settings.png",
    "link": "/",
    "type": "children",
    "children": [
      {
        "label": {
          "en": "Personal Profile"
        },
        "link": "/account",
        "type": "basic"
      },
      {
        "label": {
          "en": "Subscription Management"
        },
        "link": "/account/subscription",
        "type": "basic"
      },
      {
        "label": {
          "en": "Alerts & Email Settings"
        },
        "link": "/account/#notifications",
        "type": "basic"
      }
    ]
  }
]

我试图迭代它,并从孩子们那里创建辅助导航。

顶级很容易搞定,第二级几乎就在那里。但是,当映射到子项(在下面的GetChildren中)时,我无法获得任何子数组,只能获得直接对象。所以,我可以获得{child.link},但{child.label.en}会返回错误。我应该更聪明地接近这个吗?

var GetChildren = React.createClass({
    render: function() {
      var childlink = this.props.data.map(function (child, i){
        return (          
            <a key = {i} href={child.link}> {child.label.en}</a>
        );
      });
      return (
        <li className="childlist">
          {childlink}
        </li>
      );
    }
  });

var MenuComponent = React.createClass({
        getInitialState: function() {         
           return {
            condition: [], 
            menuItem: []
          };
        },
        componentDidMount: function() {
          $.get(this.props.source, function(result) {
            var items = result;
            if (this.isMounted()) {
              this.setState({
                menuItem: items,
                condition: false
              });
            }
          }.bind(this));
        },
        render: function(condition) {
        PrimaryMenu = this.state.menuItem || [];

          return (
            <aside>
              <nav>
              <ul>
              {PrimaryMenu.map(function(el, i){
                if (el.type == "basic") {
                  var PrimaryMenuLink = el.link;
                } else {
                  PrimaryMenuLink = '/' +el.label.en.toLowerCase();
                }               
                  return <li key={i}> <a data-nav={'nav-' + el.label.en.toLowerCase()}>
                  {el.label.en}</a></li>

              })}
              </ul>
              </nav> 
                 {PrimaryMenu.map(function(el, i){
                if (el.type == "children") {
                  return <section key={i} id={'nav-' + el.label.en.toLowerCase()}><ul><GetChildren data={el.children}/> </ul></section>
                }               

              })}

              </aside>           
          );
        }
      });

1 个答案:

答案 0 :(得分:1)

问题可能来自某些没有label属性的json节点。喜欢这个节点:

{
   "type": "space"
},

因此,在阅读label时,它会在en属性上生成“无法读取未定义的属性”。

您应该验证所有children个节点以确保label存在。验证link也是为了避免将undefined作为href道具