【问题标题】:ReactJS: replacing object from array with new value replaces whole arrayReactJS:用新值替换数组中的对象替换整个数组
【发布时间】:2020-01-16 22:07:02
【问题描述】:

我有数组selectedItems,当我尝试更新现有对象时:

i.e. [{lable: "one", uniqueId: 1}, {lable: "two", uniqueId: 1}] 

到:

i.e. [{lable: "one", uniqueId: 1}, {lable: "two", uniqueId: 3}]

它将整个数组替换为:

 [ { lable: "two", uniqueId: 3 }]

我怎样才能避免这种情况?

handleChange = (label, uniqueId) => {
  const { selectedItems } = this.state
  const findExistingItem = selectedItems.find((item) => {
    return item.uniqueId === uniqueId;
  })

  if(findExistingItem) {
    selectedItems.splice(findExistingItem);
    this.setState(state => ({
      selectedItems: [...state.selectedItems, {
        label, uniqueId
      }]
    }))
  } else {
    this.setState(state => ({
      selectedItems: [...state.selectedItems, {
        label, uniqueId
      }]
    }))
  }
}

【问题讨论】:

  • find 返回项目...那么,您认为selectedItems.splice(findExistingItem) 会做什么?提示:什么都没有 - 你会想要 const findExistingItem = selectedItems.findIndex(..... 和 if(findExistingItem >= 0) ...或 if(~findExistingItem)
  • @JaromandaX 对。我必须指出我在哪里找到了 uniqueId 但无法用新的替换。我试过splice 和slice。我应该用什么代替拼接
  • 实际上,这也不行,因为“uniqueId”是相同的,所以可以有多个......属性名称的奇怪选择,因为它不是唯一的
  • @JaromandaX 是的,我可能应该将其更改为更合适的内容。谢谢指出
  • 你怎么打电话给handleChange?这些论点是什么意思?

标签: javascript arrays reactjs


【解决方案1】:

另一种方法是串联使用Array#filter 和Array#concat 函数,其中;

  • 在uniqueId 上不匹配的项目将被过滤。这将替换您当前解决方案的 find() 逻辑,然后是,
  • 调用concat() 方法将新的“替换项”附加到过滤数组的末尾

在可以这样实现的代码中:

handleChange = (label, uniqueId) => {
  const {
    selectedItems
  } = this.state

  this.setState({
    selectedItems : selectedItems
      /* Filter any existing item matching on uniqueId */
      .filter(item => (item.uniqueId !== uniqueId))
      /* Append replacement { label, uniqueId } to state array */
      .concat([ { label, uniqueId } ])
  });
}

【讨论】:

  • handleChange 的哪些参数组合会将[{lable: "one", uniqueId: 1}, {lable: "two", uniqueId: 1}] 更改为[{lable: "one", uniqueId: 1}, {lable: "two", uniqueId: 3}]?
【解决方案2】:

如果省略.splice 的第二个参数(要删除的元素数),它会从索引中删除所有元素:

  const arr = [1, 2, 3];
  arr.splice(0);
  console.log(arr);

你可能只想拼接1,你可能想从元素索引开始,而不是它的值。

【讨论】:

  • 那么,arr.splice({lable: "two", uniqueId: 1}); 是做什么的?
  • OP 可能会出乎意料:p
【解决方案3】:

我认为这个问题具有误导性

我认为 OP 想要做的是找到传递给函数的标签并更改匹配数组条目的 uniqueId - 假设结果为 [{lable: "two", uniqueId: 3}] 意味着正在调用 handleChange

handleChange('two', 3);

鉴于逻辑更像以下

handleChange = (label, uniqueId) => {
    this.setState(state => ({
        selectedItems: state.selectedItems.map(item => Object.assign(item, item.lable === label ? {uniqueId} : {}))
    });
}

为了说明这项工作:

const handleChange = (label, uniqueId) => {
    const selectedItems = [{lable: "one", uniqueId: 1}, {lable: "two", uniqueId: 1}];
    return selectedItems.map(item => Object.assign(item, item.lable === label ? {uniqueId} : {}))
};

console.log(handleChange('two', 3));

或者“借用”一些更好的代码,然后修复它

handleChange = (lable, uniqueId) => {
    const { selectedItems } = this.state
    const selectedItem = selectedItems.filter(item => item.lable !== lable)
    this.setState({  selectedItems:  [...selectedItem, { lable, uniqueId }] })
}

证明它可以工作并产生预期的结果:

const handleChange = (lable, uniqueId) => {
    const selectedItems = [{lable: "one", uniqueId: 1}, {lable: "two", uniqueId: 1}];
    const selectedItem = selectedItems.filter(item => item.lable !== lable)
    return({  selectedItems:  [...selectedItem, { lable, uniqueId }] })
};

console.log(handleChange('two', 3));

【讨论】:

    【解决方案4】:

    可以过滤和设置状态

    handleChange = (label, uniqueId) => {
      const { selectedItems } = this.state
      // filter data if exists other wise return present array
      const selectedItem = selectedItems.filter(item => item.uniqueId !== uniqueId)
    
      this.setState({  selectedItems:  [...selectedItem, { label, uniqueId }] })
    }
    

    根据 uniqueId 过滤切片,如果不存在则追加新的

    【讨论】:

    • 基本上与重构后接受的答案相同的代码......所以,让我问你,handleChange 的哪些参数组合会将[{lable: "one", uniqueId: 1}, {lable: "two", uniqueId: 1}] 更改为[{lable: "one", uniqueId: 1}, {lable: "two", uniqueId: 3}]?
    【解决方案5】:

    Array.find() 在数组中查找元素并返回其引用。

    可以修改返回的对象,然后更新状态。

    另外,您可以更改find() 条件以通过以下方式查找项目 label 或 uniqueId 根据您的需要。得到你的输出 问题,你必须找到label 而不是uniqueId。

    handleChange = (label, uniqueId) => {
      const { selectedItems } = this.state;
    
      const findExistingItem = selectedItems.find((item) => {
        // To find by 'label', replace 'uniqueId' below with 'label'.
        return item.uniqueId === uniqueId;
      })
    
      if(findExistingItem) {
        // You are not passing in 'newUniqueId', so only 'label' is updated.
        findExistingItem.label = label;
        findExistingItem.uniqueId = uniqueId;
      } 
    
      this.setState(state => ({
        selectedItems: selectedItems
      }));
    }
    

    实例:

    function handleChange(label, uniqueId) {
    
      const selectedItems = [{label: "one",uniqueId: 1}, {label: "two", uniqueId: 1 }];
    
      const findExistingItem = selectedItems.find(item => { 
         // Finding by 'label', change to 'uniqueId' if that is what is needed.
         return item.label === label;
      });
    
      if(findExistingItem) {
        findExistingItem.label = label;
        findExistingItem.uniqueId = uniqueId;
      } 
     
      console.log(JSON.stringify(selectedItems));
    }
    
    handleChange("two", 3);

    【讨论】:

    • handleChange 的哪些参数组合会将[{lable: "one", uniqueId: 1}, {lable: "two", uniqueId: 1}] 更改为[{lable: "one", uniqueId: 1}, {lable: "two", uniqueId: 3}]?
    • @JaromandaX - handleChange("two", 1) 将更改对象的标签,但 uniqueId 不会更改,因为我们使用相同的 uniqueId 来首先查找元素。 OP 没有通过newUniqueId。您应该就此向 OP 询问,但为什么要对页面上的每个答案都投反对票?
    • 因为你们都没有产生预期的输出 - 因此“这个答案没有用”......没有产生所需的结果
    • 所需的结果是修复 OP 的错误,而不是更改他的输入。我看到了你的回答,你认为label 是过滤标准,你怎么能假设当 OP 自己在问题本身中使用了uniqueId 时?
    • @JaromandaX - 也适用于我的。删除不赞成票,因为我现在也解决了这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-23
    • 2017-11-07
    • 2016-10-01
    • 1970-01-01
    • 2018-10-03
    • 2015-03-31
    • 1970-01-01
    相关资源
    最近更新 更多