简体   繁体   中英

React 16 iterating over map rendering key

I am trying to iterate over an Immutable.js map, to render a component, however although this is rendering, it is also rendering the key to the page. I am not sure why.

render() {
    const myMap = new Map({foo: '', bar: 'http://google.com/'})
    const {showFoo, titleAndUrl} = this.props
    return (
      <ul style={[
        styles.container,
        showFoo && styles.container.inline,
      ]}>
        {myMap.map((title, url) => this.renderTab(url, title))}
      </ul>
    )
  }

  renderTab(title, url) {
    const {showFoo, isFoo} = this.props
    return (
      <li key="sb" style={[
        styles.listItem,
        showFoo && styles.listItem.inline,
      ]}>
        <a
          href={url}
          key={title}
          style={[
            styles.link,
            styles.activeLink,
            showFoo && styles.link.inline,
          ]}
          className={isFoo ? "style" : ''}>
          {title}
        </a>
      </li>
    )
  }
}

The two names and urls are rendered correctly, however duplicate keys are rendered ie foo is rendered twice and so is bar, but one of the foo and bar keys has no styles, which suggests it's being rendered outside of this.renderTab

See image: 在此处输入图片说明

Rendered HTML:

<ul data-radium="true"
    style="display: flex; align-items: center; padding: 0px; margin: 0px; list-style: none; width: 100%; border-top: 1px solid rgb(221, 221, 221); height: 48px;">
    foo
    <li data-radium="true" style="display: flex; width: 50%; height: 47px; cursor: default;"><a href=""
                                                                                                class=""
                                                                                                data-radium="true"
                                                                                                style="display: flex; justify-content: center; align-items: center; width: 100%; text-decoration: none; font-weight: 500; font-size: 16px; color: rgb(0, 31, 91); transition: color 0.1s linear;">foo</a>
    </li>
    bar
    <li data-radium="true" style="display: flex; width: 50%; height: 47px; cursor: default;"><a
            href="http://google.com" class="" data-radium="true"
            style="display: flex; justify-content: center; align-items: center; width: 100%; text-decoration: none; font-weight: 500; font-size: 16px; color: rgb(0, 31, 91); transition: color 0.1s linear;">bar</a>
    </li>
</ul>

You have mixed up the order of your arguments, assigning title to url and vice versa.

Also, the arguments passed to the callback function for Immutable.Map.map are (1) value, (2) key, so the fist argument is your URL and the second is your title.

Change the line with the call to map like so:

{myMap.map((url, title) => this.renderTab(title, url))}

Another problem is that the list item elements you are rendering all have the same key “sb”, only the key of the “a” elements change, but that is not even needed.

Change the JSX returned by renderTab to this:

  <li key={title} style={[
    styles.listItem,
    showFoo && styles.listItem.inline,
  ]}>
    <a
      href={url}
      style={[
        styles.link,
        styles.activeLink,
        showFoo && styles.link.inline,
      ]}
      className={isFoo ? "style" : ''}>
      {title}
    </a>
  </li>

Finally, the main mistake is that you expect Immutable.Map.map to return an array, but it doesn't, it returns another immutable map, so you have to convert the value returned by the map function to an array using valueSeq and toArray .

So your map statement should actually look like this:

{myMap.map((url, title) => this.renderTab(title, url)).valueSeq().toArray()}

see related post on Stack Overflow

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM