列表渲染

推荐: JSX 中用 .map 渲染

列表中 key 值的唯一性

/**
 * Each child in a list should have a unique "key" prop.
 * 列表中的每个子元素都必需一个唯一的key属性值
 * key 是 React 查看元素是否改变的一个唯一标识 key必须在「兄弟」节点中唯一,确定的。
 * 一个 table 中,两次 map 循环时,相互之间的 key 不用唯一,这里的兄弟节点是只一次 map 循环出来的东西之间的唯一
 */

禁止使用 index 作为 key 值

/**
 * 不建议使用 index 做为 key 值(禁止)
 *  建立在列表顺序改变、元素增删的情况下
 * 
 * 列表项增删或顺序改变了,index 的对应项就会改变
 * key 对应的项还是之前列表情况的对应元素的值
 * 导致状态 (arr) 混乱,查找元素性能就会变差
 * 
 * 好的做法:
 *  如果列表是静态不可操作的,可以选择 index 作为key,但也不推荐
 *  很有可能这个列表在以后维护扩展的时候,有可能变更为可操作的列表
 * 
 *  1. 尽量避免使用 index
 *  2. 可以用数据的ID(但有可能ID会变动)
 *  3. 最好使用动态生成一个静态ID nanoid
 */
// 前提: npm install nanoid
import { nanoid } from 'nanoid'

class App extends React.Component {
  state = {
    arr: [
      {
        id: 1,
        name: 'Lance'
      },
      {
        id: 2,
        name: 'Sherry'
      },
      {
        id: 3,
        name: 'Jerry'
      }
    ]
  }
  render() {
    const { arr } = this.state
    return (
      <table border="1">
        <thead>
          <tr>
            <th>KEY</th>
            <th>ID</th>
            <th>NAME</th>
          </tr>
        </thead>
        <tbody>
          {
            arr.map(v => {
              const key = nanoid()
              return (
                <tr key={ key }>
                  <td>{ key }</td>
                  <td>{ v.id }</td>
                  <td>{ v.name }</td>
                </tr>
              )
            })
          }
          {/* 上下两次 map , 相互之间的 key 不用唯一 */}
          {
            arr.map(v => {
              const key = nanoid()
              return (
                <tr key={ key }>
                  <td>{ key }</td>
                  <td>{ v.id }</td>
                  <td>{ v.name }</td>
                </tr>
              )
            })
          }
        </tbody>
      </table>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
)

组件拆分

import { nanoid } from 'nanoid'
class ItemTitle extends React.Component {
  render() {
    return (
      <thead>
        <tr>
          <th>KEY</th>
          <th>ID</th>
          <th>NAME</th>
        </tr>
      </thead>
    )
  }
}

class ListItem extends React.Component {
  render() {
    const { sid, item } = this.props
    return (
      <tr>
        <td>{ sid }</td>
        <td>{ item.id }</td>
        <td>{ item.name }</td>
      </tr>
    )
  }
}

class App extends React.Component {
  state = {
    arr: [
      {
        id: 1,
        name: 'Lance'
      },
      {
        id: 2,
        name: 'Sherry'
      },
      {
        id: 3,
        name: 'Jerry'
      }
    ]
  }
  render() {
    return (
      <table border="1">
        <ItemTitle />
        <tbody>
          {
            this.state.arr.map(v => {
              const sid = nanoid()
              /**
               * key 是不会作为属性传递给子组件的,必须显式传递 key 值
               * 目的: 防止开发者在逻辑中对 key 进行操作
               */
              return (
                <ListItem key={ sid } sid={ sid } item={ v } />
              )
            })
          }
        </tbody>
      </table>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
)