【问题标题】:Using object instance as a key in React list使用对象实例作为 React 列表中的键
【发布时间】:2018-08-07 12:20:42
【问题描述】:

我有一个对象列表,我想使用 React 将其呈现为列表。

React 需要列表元素上的特殊 key 属性来跟踪 DOM 和虚拟 DOM 之间的变化。

我的对象没有像id这样的特殊的唯一属性,事实上,两个对象甚至可以具有相同的属性,但对象本身是唯一的。

有没有办法使用对象的引用作为渲染 React 列表的键?

否则,在这种情况下可以建议哪些解决方法?


另外,我从第三方接收项目列表,所以我不能只为每个项目附加一个随机 ID,因为它会使 React 在我每次收到更新数据时重新渲染所有项目.

【问题讨论】:

  • 我建议生成随机 id。例如来自lodash
  • 在钥匙上附加一个计数器?
  • 通常的做法是为您的对象附加一个“虚拟”id,或者如果数组元素的顺序不会改变,您可以使用index of the array as key as last resort
  • 每次渲染生成一个随机 ID 是没有意义的,您应该在创建对象/从服务器接收它们时生成它们(或者只是在服务器上进行)
  • 如果我在收到每个项目时将生成的虚拟 ID 附加到每个项目上,React 会不会在我收到更新数据时重新渲染所有项目?

标签: reactjs react-dom


【解决方案1】:

如果你没有唯一ID(由后端返回,或者你无法在前端构建复合键),那么你可以使用数组索引作为键:

render() {
  return array.map((item, index) => <Item key={index} />)
}

如果没有唯一的 ID,无论您选择哪种方法,如果项目的顺序发生变化,那么列表可能会完全混乱。

如果您的案例满足以下 3 个条件,使用这种方法就足够安全了,感谢this article

  1. 列表和项目是静态的——它们不会被计算也不会改变。
  2. 列表中的项目没有 ID。
  3. 列表永远不会重新排序或过滤。

【讨论】:

  • 如果项目顺序发生变化怎么办?
  • 我扩展了答案 - 当这种方法足够安全时。
【解决方案2】:

将数组的index 用作key 将是一场灾难,因为如果数组更改,视图将无法正确更新或以不可预知的方式部分更新。

我发现的唯一解决方案是按照 cmets 中的建议生成虚拟 ID。

这个想法是实现生成器,它将为每个项目创建一个 ID,但同时会记住以前生成的 ID。

WeakMap JavaScript 类将允许我们存储项目对象引用和生成的 ID 之间的映射信息:

export class IdGenerator {

  // Using WeakMap as index
  map = new WeakMap();

  // Internal counter
  lastId = 0;

  getItemId(item) {

    // Getting previously generated ID for the specified item
    let id = this.map.get(item);

    // If item is new, generating the ID and storing it for future use
    if (undefined === id) {
      id = ++(this.lastId);
      this.map.set(item, id);
    }

    // Returning ID to the caller in either case
    return id;

  }

}

然后它可以用于在渲染列表之前为每个项目分配生成的 ID:

class ListBox extends Component {

  // Instantiating the generator
  itemsIdGenerator = new IdGenerator();

  render() {
    return (
      <ul>
        {this.props.items.map(item => (
          <li key={this.itemsIdGenerator.getItemId(item)}>
            {item.title}
          </li>
        ))}
      </ul>
    );
  }

}

确保为组件的每个实例使用不同的生成器实例,并且只使用组件创建一次生成器。

此外,在组件的渲染方法中为每个项目调用生成器可能不是最佳选择。但是,我不想触摸原始项目或改变它们。如果这是一个问题,请考虑使用 React 提供的各种生命周期方法在 props 更改时设置 ID。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-06
    • 1970-01-01
    • 2013-03-02
    • 1970-01-01
    相关资源
    最近更新 更多