【问题标题】:ReactJS: using object ref as {key}?ReactJS:使用对象引用作为{key}?
【发布时间】:2021-03-16 16:47:32
【问题描述】:

如何在 ReactJS 中使用对象引用作为 {key}?

我试过了:

let ruleList = _.map(this.state.rules, function(rule) {
      return <RuleList rule={rule} key={rule} />
    });

但这最终会打印在控制台中:

警告:flattenChildren(...): 遇到两个相同的孩子 键,.0:$[object Object]。子键必须是唯一的;当两个 孩子共享一个密钥,只会使用第一个孩子。

有什么方法可以解决这个问题而不需要为每个项目生成 ID 等技巧?

【问题讨论】:

  • 规则对象有没有唯一的属性?
  • 你能提供一个规则对象的样例吗?
  • { 规则:[ ... ],折叠:真,限制:5000 }
  • 我在询问规则对象。意思是,规则数组中的一项。
  • { type: 'block', value: 'a string' }

标签: javascript reactjs


【解决方案1】:

我遇到过类似的情况,对象没有唯一 ID。

我最终根据对象引用为项目生成了 ID:

let curId = 1;
const ids = new WeakMap();

function getObjectId(object) {
  if (ids.has(object)) {
    return ids.get(object);
  } else {
    const id = String(curId++);
    ids.set(object, id);
    return id;
  }
}

// Usage
<RuleList rule={rule} key={getObjectId(rule)} />

我知道你提到你不想生成 id,但我想我会分享这个,因为它是通用的,不依赖于你对象中的任何属性。

【讨论】:

    【解决方案2】:

    我创建了一个库来解决这个问题。它基于@amann 建议的想法(使用weakMap)。它提供了一个钩子,以便weakMap随组件一起创建和销毁。

    看看https://www.npmjs.com/package/react-key-from-object

    import { useKeyGen } from 'react-key-from-object'
    
    const DogList = () => {
      const keyGen = useKeyGen();
    
      return (
        <ul>
          {dogs.map((dog) => (
            <li key={keyGen.getKey(dog)}>
              {dog.name}
              -
              {dog.age}
            </li>
          ))
        </ul>
      );
    }
    

    【讨论】:

      【解决方案3】:

      更新

      对象不能用作键。 React js 要求键是字符串或数字,并且应该是唯一的。

      IMO 有两种方法可以解决这个问题(欢迎提出建议)

      选项 1

      遍历数组并创建唯一索引

      var rules = data.rules;
      for(var i=0;i<rules.length;i++){
        data.rules[i].key = i;
      }
      

      _.map中使用这个键

      let ruleList = _.map(this.state.rules, function(rule) { 
        return <RuleList rule={rule} key={rule.key} />
      });
      

      选项 2

      维护未被删除的规则对象的索引数组。

      var N = rules.length; 
      var arrayOfRules = Array.apply(null, {length: N}).map(Number.call, Number);
      

      当您删除一个项目时,使用.splice 将其移除。

      组件应该是这样的

      let ruleList = _.map(this.state.rules, function(rule, index) { 
        return <RuleList rule={rule} key={arrayOfRules[index]} />
      });
      

      ----

      由于规则对象没有唯一的属性,key需要唯一,所以添加map方法自带的index参数。

      let ruleList = _.map(this.state.rules, function(rule, index) { // <--- notice index parameter
        return <RuleList rule={rule} key={index} />
      });
      

      【讨论】:

      • 这不起作用。当您删除前面有内容的项目时,规则引用会被前一个项目的引用破坏。
      • 对不起,我不太明白。你能解释一下吗?
      • 如果你有 [1, 2, 3, 4] 并且你删除了 1,你最终会得到 [1, 2, 3] 而不是 [2, 3, 4]。跨度>
      • @Dhiraj,你能提供任何关于键必须是字符串或数字的参考吗?
      • @BenCarp 更多信息在这里reactjs.org/docs/lists-and-keys.html#keys
      【解决方案4】:

      为什么要坚持使用规则对象作为key?

      最简单的解决方案是使用从下划线映射函数返回的索引。像这样:

      let ruleList = _.map(this.state.rules, function(rule, index) {
        return <RuleList rule={rule} key={index} />
      });
      

      这是一个与地图功能相关的similar topic

      【讨论】:

      • 这不起作用。当您删除之前有内容的项目时,规则引用会被前一个项目的引用破坏。
      • 所有对象都不同吗?在这种情况下,使用 stringify 可能会有所帮助。像这样:key={JSON.stringify(rule)}
      • 索引作为键是一种反模式medium.com/@robinpokorny/…
      • @marizikmund 这创造了奇迹。试图根据过滤器哈希更改强制子组件重新渲染。这完美地做到了。干杯。
      猜你喜欢
      • 1970-01-01
      • 2019-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多