【问题标题】:React component not updating values after element is deleted of specific index删除特定索引的元素后反应组件不更新值
【发布时间】:2021-08-21 17:14:13
【问题描述】:

我正在尝试创建一个带有删除按钮的购物清单,但是当我单击它时,其他项目被删除并且之前的值仍然保留在屏幕上,即使第二次删除也是如此。请假设自定义按钮和图标已经是单独的包这是代码 -

import React, { useState } from 'react';
import { CButton, CDeleteButton } from '@custom/pkg';

const ShoppingList = () => {

    const [state, setState] = useState(
        [{ name: 'Apple', price: 60 }, { name: 'Banana', price: 20 }]
    )

    return (
        <>
            <h2>Product List</h2>
            {state.map(({name, price}, idx) => (
                <>
                    <div key={idx}>
                        <div>{name}</div>
                        <div>{price}</div>
                        <div>
                            <CButton id={idx} onClick={() => {
                                setState((prev) => [...prev.splice(idx, 1)])
                            }}>
                                <CDeleteButton/>
                            </CButton>
                        </div>
                    </div>
                </>
            ))}
        </>
    )
}

export default ShoppingList;

这个组件被导入一个模态组件并被渲染。如果我删除"Apple",它仍然显示在屏幕上,"Banana" 被删除,反之亦然。

【问题讨论】:

  • 不要使用数组索引作为键。如果您没有每个项目的唯一标识符,最好使用&lt;div key={`${name}-${idx}`}&gt;,这样在删除元素时更难与之前的 id 发生冲突。

标签: reactjs react-hooks use-state


【解决方案1】:

问题

问题是您使用的 React 键与映射元素无关。当您插入或删除元素时,进行中的元素都会移动位置并且它们的键会发生变化,但从 React 的角度来看,该位置的键是相同的,因此 React 不会重新渲染。换句话说,当您删除中间的一个元素时,上移的元素会采用先前存在的键并且不会重新渲染。

这就是为什么如果要改变基础数据,在映射数组时使用数组索引是一个糟糕的选择。

为每个元素添加一个 GUID 或其他一些唯一属性以用作键,或者使用属性组合来生成一个。 React 键还需要位于最外层的映射元素上,在您的情况下为 Fragment。由于 map 回调中不需要片段,因此您只返回一个节点,可以将其删除。

也不建议使用.splice,因为它会就地改变数组。如果你想从数组中删除一个元素,你应该使用.slice.filter

解决方案 1

使用添加的id 属性。

const ShoppingList = () => {
  const [state, setState] = useState([
    { id: 0, name: 'Apple', price: 60 }, // add id property
    { id: 1, name: 'Banana', price: 20 },
  ]);

  const removeItem = id => () => {
    setState(prev => prev.filter((el) => el.id !== id)); // filter by id
  };

  return (
    <>
      <h2>Product List</h2>
      {state.map(({ id, name, price }) => (
        <div key={id}> // id as key
          <div>{name}</div>
          <div>{price}</div>
          <div>
            <CButton id={id} onClick={removeItem(id)}> // pass id to handler
              <CDeleteButton/>
            </CButton>
          </div>
        </div>
      ))}
    </>
  )
}

解决方案 2

使用属性中的索引和计算的 React 键。

const ShoppingList = () => {
  const [state, setState] = useState([
    { name: 'Apple', price: 60 },
    { name: 'Banana', price: 20 },
  ]);

  const removeItem = index => () => {
    setState(prev => prev.filter((el, i) => i !== index)); // filter by index
  };

  return (
    <>
      <h2>Product List</h2>
      {state.map(({ name, price }, idx) => (
        <div key={`${name}-${price}`}> // computed key
          <div>{name}</div>
          <div>{price}</div>
          <div>
            <CButton id={idx} onClick={removeItem(idx)}> // pass index to handler
              <CDeleteButton/>
            </CButton>
          </div>
        </div>
      ))}
    </>
  )
}

【讨论】:

  • 感谢@Drew Reese 的解释,现在我知道我做错了什么以及删除(y)
【解决方案2】:

你应该展开 prev 数组,然后使用splice

<CButton id={idx} onClick={()=>{setState((prev)=>[...prev].splice(idx,1))}}>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-01-13
    • 2021-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-10
    • 1970-01-01
    相关资源
    最近更新 更多