如何使用 useState 在函数式 React 中正确更新数组
How to properly update an array in functional React with useState
我遍历了 Whosebug 和 Google,但我一直无法找到以下问题的解决方案,因此我们将不胜感激。
假设我在 React 中使用 useState 钩子,并且我已经定义了一个状态元素:
const [selectedItems, setSelectedItems] = useState([]);
让我们进一步假设我想用一个对象数组更新这个数组,这样生成的数组将是我想要推入其中的所有对象的数组。所以,假设我试过这个:
let newItems = [...selectedItems];
newItems.push({a complex object});
setSelectedItems(newItems);
selectedItems 将保持 []
。
我已经尝试了六种不同的排列方式来设置这个状态,但都没有成功。我所做的一切,selectedItems 始终保持 []
.
我既需要将对象推入此数组,也需要删除它们...但我很乐意简单地替换整个数组。问题是,如果我使用功能性 React 和 useState 挂钩,我找不到如何在状态中更新此数组。正如我所说,如果像 setSelectedItems([new array of objects])
这样更新,那么状态不会改变。
我知道类似的问题已在 Whosebug 上被问过多次,但我找不到任何与此用例直接比较的示例。任何帮助将不胜感激。
您可以通过定义匿名函数在 setter 方法中使用旧状态,例如
const [selectedItems, setSelectedItems] = useState([]);
setSelectedItems((oldItems) => [...oldItems, yourNewItem])
无需通过推送解构和添加新项目,特别是如果你想发挥作用的话。
渲染方法将更新您的视图,当您正确地迭代它并使用键告诉 React 哪些对象是哪些时。
编辑:为了证明这是有效的,这里有一个有效的演示。如果它不适合你,你可能以某种方式使用了你的数组,其中反应无法区分数组之间的区别,因此不会有可见的重新渲染。
const Demo = () => {
const [selectedItems, setSelectedItems] = React.useState(["a", "b", "c"]);
const removeItem = (item) => {
setSelectedItems((oldItems) => [
...oldItems.filter(i => i !== item),
`Removed item ${item}`
])
}
return (<div>
{selectedItems.map(item => <button key={"item-"+item}
onClick={() => removeItem(item)}>Remove Item {item}</button>)}
</div>);
}
ReactDOM.render(<Demo />, document.querySelector("#app"))
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id="app"></div>
重新发布答案,因为之前答案中的 link 无效
你可以试试这样的
const [items, setItems] = useState([])
let updatedList = [...items, ...moreItems]
setItems(updatedList)
其中“moreItems”又是一个对象数组。如果你想添加单个对象,你可以试试这个
let updatedList = [...items, {key : 'value'}]
setItems(updatedList)
检查这个 link 用一个工作示例 https://stackblitz.com/edit/react-6enrwj
我遍历了 Whosebug 和 Google,但我一直无法找到以下问题的解决方案,因此我们将不胜感激。
假设我在 React 中使用 useState 钩子,并且我已经定义了一个状态元素:
const [selectedItems, setSelectedItems] = useState([]);
让我们进一步假设我想用一个对象数组更新这个数组,这样生成的数组将是我想要推入其中的所有对象的数组。所以,假设我试过这个:
let newItems = [...selectedItems];
newItems.push({a complex object});
setSelectedItems(newItems);
selectedItems 将保持 []
。
我已经尝试了六种不同的排列方式来设置这个状态,但都没有成功。我所做的一切,selectedItems 始终保持 []
.
我既需要将对象推入此数组,也需要删除它们...但我很乐意简单地替换整个数组。问题是,如果我使用功能性 React 和 useState 挂钩,我找不到如何在状态中更新此数组。正如我所说,如果像 setSelectedItems([new array of objects])
这样更新,那么状态不会改变。
我知道类似的问题已在 Whosebug 上被问过多次,但我找不到任何与此用例直接比较的示例。任何帮助将不胜感激。
您可以通过定义匿名函数在 setter 方法中使用旧状态,例如
const [selectedItems, setSelectedItems] = useState([]);
setSelectedItems((oldItems) => [...oldItems, yourNewItem])
无需通过推送解构和添加新项目,特别是如果你想发挥作用的话。
渲染方法将更新您的视图,当您正确地迭代它并使用键告诉 React 哪些对象是哪些时。
编辑:为了证明这是有效的,这里有一个有效的演示。如果它不适合你,你可能以某种方式使用了你的数组,其中反应无法区分数组之间的区别,因此不会有可见的重新渲染。
const Demo = () => {
const [selectedItems, setSelectedItems] = React.useState(["a", "b", "c"]);
const removeItem = (item) => {
setSelectedItems((oldItems) => [
...oldItems.filter(i => i !== item),
`Removed item ${item}`
])
}
return (<div>
{selectedItems.map(item => <button key={"item-"+item}
onClick={() => removeItem(item)}>Remove Item {item}</button>)}
</div>);
}
ReactDOM.render(<Demo />, document.querySelector("#app"))
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id="app"></div>
重新发布答案,因为之前答案中的 link 无效
你可以试试这样的
const [items, setItems] = useState([])
let updatedList = [...items, ...moreItems]
setItems(updatedList)
其中“moreItems”又是一个对象数组。如果你想添加单个对象,你可以试试这个
let updatedList = [...items, {key : 'value'}]
setItems(updatedList)
检查这个 link 用一个工作示例 https://stackblitz.com/edit/react-6enrwj